# 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; }}>
); }; export default App; ``` ```ts import { AdaptableOptions } from '@adaptabletools/adaptable'; import { SystemFilterPredicateId, SystemPredicatesContext, } from '@adaptabletools/adaptable-react-aggrid'; import { useState } from 'react'; import { TimezoneSelect } from './TimezoneSelect'; import * as React from 'react'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom Predicate Override Implementation', stateOptions: { loadState: () => Promise.resolve({}) }, predicateOptions: { customPredicateDefs: [ { id: 'Now', extends: 'Today', label: 'Now', handler: ({ value, adaptableContext }) => { return adaptableContext.zonedDateTimeService.isToday(value); }, }, { id: 'Yesterday', extends: 'Yesterday', handler: ({ value, adaptableContext }) => adaptableContext.zonedDateTimeService.isYesterday(value), }, { id: 'Tomorrow', extends: 'Tomorrow', handler: ({ value, adaptableContext }) => adaptableContext.zonedDateTimeService.isTomorrow(value), }, { id: 'InPast', extends: 'InPast', handler: ({ value, adaptableContext }) => adaptableContext.zonedDateTimeService.isPast(value), }, { id: 'InFuture', extends: 'InFuture', handler: ({ value, adaptableContext }) => adaptableContext.zonedDateTimeService.isFuture(value), }, ], systemFilterPredicates: ( context: SystemPredicatesContext ) => { return context.systemPredicateDefs .map(predicate => predicate.id) .filter(predicate => { return ( predicate !== 'ThisWeek' && predicate !== 'ThisMonth' && predicate !== 'ThisQuarter' && predicate !== 'ThisYear' && predicate !== 'NextWorkDay' && predicate !== 'LastWorkDay' && predicate !== 'WorkDay' && predicate !== 'Holiday' ); }); }, }, dashboardOptions: { customToolbars: [ { name: 'TimezoneSelector', title: 'Timezone Info', frameworkComponent: ({ adaptableApi }) => { const [timeZone, setTimeZone] = useState( adaptableApi.optionsApi.getAdaptableContext().zonedDateTimeService ); return (
{ setTimeZone( adaptableApi.optionsApi.getAdaptableContext() .zonedDateTimeService ); // re-evaluate grid filters adaptableApi.agGridApi.onFilterChanged(); }} />
); }, }, ], }, initialState: { Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'taskName', 'dueDate', 'assignee', 'priority', 'status', ], ColumnSizing: { taskName: { Width: 149 }, dueDate: { Width: 200 }, assignee: { Width: 193 }, priority: { Width: 105 }, status: { Width: 118 }, }, ColumnSorts: [ { ColumnId: 'dueDate', SortOrder: 'Asc', }, ], ColumnFilters: [ { ColumnId: 'dueDate', Predicates: [ { PredicateId: 'Now', }, ], }, ], AutoSizeColumns: true, }, ], }, Theme: { CurrentTheme: 'dark' }, FormatColumn: { FormatColumns: [ { Name: 'date-format', Scope: { DataTypes: ['date'], }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'yyyy-MM-dd HH:mm:ss', }, }, }, ], }, Dashboard: { Tabs: [ { Name: 'Default', Toolbars: ['TimezoneSelector'], }, ], }, }, }; ``` ```ts import {DateTime} from 'luxon'; interface TimezoneInfo { // e.g. 'America/New_York' name: string; // e.g. '-05:00' offset: string; } export class ZonedDateTimeService { private activeTimezoneName: string; public readonly timeZones: {name: string; offset: string}[]; constructor() { const browserTimezoneInfo = this.getCurrentBrowserTimezone(); this.activeTimezoneName = browserTimezoneInfo.name; const timeZones = [ browserTimezoneInfo, {name: 'Europe/London', offset: 'UTC'}, {name: 'America/New_York', offset: '-05:00'}, {name: 'Pacific/Honolulu', offset: '-10:00'}, {name: 'Asia/Kolkata', offset: '+05:30'}, {name: 'Asia/Tokyo', offset: '+09:00'}, ].sort((a, b) => a.name.localeCompare(b.name)); this.timeZones = timeZones; } public setActiveTimezoneName(timezoneName: string): void { this.activeTimezoneName = timezoneName; } public getActiveTimezoneName(): string { return this.activeTimezoneName; } getCurrentBrowserTimezone(): TimezoneInfo { const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; const browserOffset = DateTime.local() .setZone(browserTimezone) .toFormat('ZZ'); return {name: browserTimezone, offset: browserOffset}; } getCurrentZonedTime(): DateTime { return DateTime.now().setZone(this.activeTimezoneName); } getCurrentLocalTime(): DateTime { return DateTime.now(); } isToday(date: string | number | Date): boolean { const parsedInputDate = this.parseDateValue(date); if (!parsedInputDate) { return false; } const currentDate = this.getCurrentZonedTime(); const inputDate = DateTime.fromJSDate(parsedInputDate).setZone( this.activeTimezoneName ); return this.isSameDay(currentDate, inputDate); } isYesterday(date: string | number | Date): boolean { const parsedInputDate = this.parseDateValue(date); if (!parsedInputDate) { return false; } const currentDate = this.getCurrentZonedTime(); const inputDate = DateTime.fromJSDate(parsedInputDate).setZone( this.activeTimezoneName ); return this.isSameDay(currentDate.minus({days: 1}), inputDate); } isTomorrow(date: string | number | Date): boolean { const parsedInputDate = this.parseDateValue(date); if (!parsedInputDate) { return false; } const currentDate = this.getCurrentZonedTime(); const inputDate = DateTime.fromJSDate(parsedInputDate).setZone( this.activeTimezoneName ); return this.isSameDay(currentDate.plus({days: 1}), inputDate); } isPast(date: string | number | Date): boolean { const parsedInputDate = this.parseDateValue(date); if (!parsedInputDate) { return false; } const currentDate = this.getCurrentZonedTime(); const inputDate = DateTime.fromJSDate(parsedInputDate).setZone( this.activeTimezoneName ); return inputDate < currentDate; } isFuture(date: string | number | Date): boolean { const parsedInputDate = this.parseDateValue(date); if (!parsedInputDate) { return false; } const currentDate = this.getCurrentZonedTime(); const inputDate = DateTime.fromJSDate(parsedInputDate).setZone( this.activeTimezoneName ); return inputDate > currentDate; } getStartOfToday(): Date { return DateTime.now() .setZone(this.activeTimezoneName) .startOf('day') .toJSDate(); } parseDateValue(input: string | number | Date): Date | null { if (input instanceof Date) { return input; } let date; // Check if input is a number if (typeof input === 'number') { date = DateTime.fromMillis(input).toJSDate(); } else if (typeof input === 'string') { // Check if input can be parsed as a number (timestamp) const timestamp = Date.parse(input); if (!isNaN(timestamp)) { date = DateTime.fromMillis(timestamp).toJSDate(); } else { // Try parsing as ISO 8601 date string date = DateTime.fromISO(input); // If the date is invalid, set date to null if (!date.isValid) { date = null; } else { date = date.toJSDate(); } } } return date as Date | null; } private isSameDay(dateA: DateTime, dateB: DateTime): boolean { return dateA.hasSame(dateB, 'day'); } } ``` ```ts import React, {useEffect, useState} from 'react'; import {ZonedDateTimeService} from './ZonedDateTimeService'; export interface TimezoneSelectProps { timezoneService: ZonedDateTimeService; onChange: (timezone: string) => void; } export const TimezoneSelect: React.FC = ({ timezoneService, onChange, }) => { const handleTimezoneChange = ( event: React.ChangeEvent ) => { const newTimezone = event.target.value; timezoneService.setActiveTimezoneName(newTimezone); onChange(newTimezone); }; const [timezoneDateTime, setTimezoneDateTime] = useState( timezoneService.getCurrentZonedTime() ); useEffect(() => { const timer = setInterval( () => setTimezoneDateTime(timezoneService.getCurrentZonedTime()), 500 ); return function cleanup() { clearInterval(timer); }; }, []); return (
{timezoneDateTime.toFormat('yyyy-MM-dd HH:mm:ss')}
); }; ``` ```ts export interface TaskInfo { id: number; taskName: string; assignee: string; priority: string; status: string; dueDate: string; } // generates random data for the grid export const getRowData = () => { const rowData = []; for (let i = 1; i <= 50; i++) { rowData.push({ id: i, taskName: `Task ${i}`, assignee: getRandomAssignee(), priority: getRandomPriority(), status: getRandomStatus(), // the `dueDate` field gets a random date between 2 days ago and 2 days from now dueDate: generateRandomDueDate(), }); } return rowData; }; const fakeNames = [ 'John Doe', 'Alice Smith', 'Bob Johnson', 'Emily Davis', 'Michael Wilson', 'Sophia Brown', 'William Lee', 'Olivia Clark', 'James Garcia', 'Charlotte Martinez', 'Daniel Anderson', 'Mia Taylor', 'David Hernandez', 'Ella Gonzalez', 'Logan Perez', 'Ava Carter', 'Matthew Scott', 'Grace Murphy', 'Lucas Hall', 'Chloe King', ]; function getRandomAssignee() { return fakeNames[Math.floor(Math.random() * fakeNames.length)]; } function getRandomPriority() { const priorities = ['High', 'Medium', 'Low']; return priorities[Math.floor(Math.random() * priorities.length)]; } function getRandomStatus() { const statuses = ['In Progress', 'Pending', 'Completed']; return statuses[Math.floor(Math.random() * statuses.length)]; } function generateRandomDueDate() { const currentDate = new Date(); // Current date and time const startDate = new Date(currentDate); startDate.setDate(startDate.getDate() - 2); // Set start date to 2 days ago const endDate = new Date(currentDate); endDate.setDate(endDate.getDate() + 2); // Set end date to 2 days later const randomDate = new Date( startDate.getTime() + Math.random() * (endDate.getTime() - startDate.getTime()) ); return randomDate.toISOString(); } ``` ```ts import {ColDef} from 'ag-grid-enterprise'; export const columnDefs: ColDef[] = [ { headerName: 'ID', field: 'id', cellDataType: 'number', hide: true, }, {headerName: 'Task Name', field: 'taskName', cellDataType: 'text'}, { headerName: 'Assignee', field: 'assignee', cellDataType: 'text', enablePivot: true, enableRowGroup: true, enableValue: true, }, { headerName: 'Priority', field: 'priority', cellDataType: 'text', enablePivot: true, enableRowGroup: true, enableValue: true, }, { headerName: 'Status', field: 'status', cellDataType: 'text', enablePivot: true, enableRowGroup: true, enableValue: true, }, {headerName: 'Due Date (UTC)', field: 'dueDate', cellDataType: 'date'}, ]; ``` ```ts skipFile=adaptableOptions.ts ``` ```ts skipFile=onAdapterReady.ts ``` In the example above, we overrode the `handler` property in order to provide a new implementation for some System Predicates. But any property in a System Predicate can be overridden; the behaviour is as follows: - Properties provided in the Custom Predicate will replace their equivalents in the System Predicate - Properties not expressly provided in the Custom Predicate will use that provided by the System Predicate This allows you just to provide a new `label`, or `icon` for the Predicate and leave the implementation untouched **Example: Custom Predicates overriding System Predicates Props** Overriding System Predicate labels and icons - In this example we extend 4 System Predicates by providing properties other than `handler`: - `LessThan` and `GreaterThan` have new labels of "Fewer" and "More" respectively - `Contains` and `NotContains` have been given different icons ```ts import { AdaptableOptions, PredicateDefHandlerContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom Predicates Override Props', predicateOptions: { customPredicateDefs: [ { id: 'GreaterThan', extends: 'GreaterThan', label: 'More', }, { id: 'LessThan', extends: 'LessThan', label: 'Fewer', }, { id: 'Contains', extends: 'Contains', icon: { name: 'plus', }, }, { id: 'NotContains', extends: 'NotContains', icon: { name: 'error', }, }, ], }, initialState: { StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['ColumnFilter'], }, ], }, Theme: {CurrentTheme: 'dark'}, 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: 'github_stars', Predicates: [{PredicateId: 'LessThan', Inputs: [20000]}], }, { ColumnId: 'language', Predicates: [{PredicateId: 'NotContains', Inputs: ['HTML']}], }, ], AutoSizeColumns: true, }, ], }, }, }; ``` --- # System Predicates Canonical page: https://www.adaptabletools.com/docs/adaptable-predicate-system - AdapTable supplies a large number of System Predicates - System Predicates are small boolean functions evaluated by AdapTable - They are primarily used in Filters but can also be used in Alerts, Flashing Cells and Format Column Modules AdapTable provides a large number of Predicates available for both developers and end users. - Additionally, developers can provide [Custom Predicate Definitions](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) to supplement System Predicates - Alternatively they can be used to [override the default System Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md#overriding-system-predicates) behaviour with custom behavior These are all different instances of the [`AdaptablePredicate`](https://www.adaptabletools.com/docs/reference/adaptablepredicate.md) object, which comprises a number of properties which allow AdapTable to know where, how and when to display it. ### Anatomy of a System Predicate Every AdapTable Predicate is based on an [`Adaptable Predicate Definition`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md). The key property is `handler` which provides the function that AdapTable will use for evaluation. For instance the `Blanks` predicate will check all column types to see if the value is empty, while the `Positive` predicate will check the value of a number cell to see if its greater than 0. Another property is `columnScope` which for all System Predicates is linked to a DataType (but [Custom Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) can specify particular columns). Here is the definition of the `GreaterThan` Predicate which receives a single numeric input. Note that in addition to `name`, `handler`, `columnScope` and `moduleScope` it also defines the icon to be used and any Filter Bar shortcuts that can be applied. ``` { id: 'GreaterThan', label: 'Greater Than', icon: { path: 'greater-than' }, columnScope: { DataTypes: ['number'] }, moduleScope: ['columnFilter', 'alert', 'formatcolumn', 'badgeStyle'], inputs: [{ type: 'number' }], handler: ({ value, inputs }) => Number(value) > Number(inputs[0]), toString: ({ inputs }) => `> ${inputs[0]}`, shortcuts: ['>'] } ``` ## Managing System Predicates By default **all** System Predicates are available in Modules to which they have the correct Scope. The Appendix below lists which System Predicates are available by default to each Module However developers are able to list / manage which System Predicates are present in AdapTable if required. This is done via 5 properties in [Predicate Options](https://www.adaptabletools.com/docs/adaptable-predicate-technical-reference/index.md): | Type | Predicates Returned | Where Available | | ------------------------------ | -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `systemFilterPredicates` | [`SystemFilterPredicateIds`](https://www.adaptabletools.com/docs/reference/systemfilterpredicateids.md) | [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) | | `systemFormatColumnPredicates` | [`SystemFormatColumnPredicateIds`](https://www.adaptabletools.com/docs/reference/systemformatcolumnpredicateids.md) | [Format Column Conditions](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) | | `systemAlertPredicates` | [`SystemAlertPredicateIds`](https://www.adaptabletools.com/docs/reference/systemalertpredicateids.md) | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) | | `systemFlashingCellPredicates` | [`SystemFlashingCellPredicateIds`](https://www.adaptabletools.com/docs/reference/systemflashingcellpredicateids.md) | [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) | | `systemBadgeStylePredicates` | [`SystemBadgeStylePredicateIds`](https://www.adaptabletools.com/docs/reference/systembadgestylepredicateids.md) | [Badge Styles](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md) | ### Using the System Predicate properties Each of the 5 properties work similarly, allowing System Predicates for that Module to be provided. The examples here use System Filters but the same logic is identical for all 5 properties The properties all return data in one of 2 ways: Providing a List The simplest way to set System Predicates is to provide a List of available values: ```ts {4} // Only make 3 (of the many) System Filters available const adaptableOptions: AdaptableOptions = { predicateOptions: { systemFilterPredicates: ['Positive', 'Today', 'Blanks'], } }; ``` Alternatively you can provide an empty array if you want **no** System Predicates to be available for the Module: ```ts {3} const adaptableOptions: AdaptableOptions = { predicateOptions: { systemFilterPredicates: [], } }; ``` Providing a Function Alternatively a JavaScript function can be provided. The function receives an object of type [`SystemPredicatesContext`](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md) and returns a list of Predicates. The major property in the `SystemPredicatesContext` object is a list of all the System Predicate Definitions for that Module. The function, therefore, allows you to filter out the items you dont want like this: ```ts {4,5,6,7,8,9} // 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; }, } }; ``` ## Appendix: System Predicate List This is the full list of Predicates shipped by AdapTable together with where they can be applied: | [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 | [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) | [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) | [Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) | [Badge Style](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md) | | ----------------------------------------------------------- | :-----------------------------------------------------------------------------: | :----------: | :-----------------------------------------------------------------: | :----------------------------------------------------: | :-----------------------------------------------------------------: | :--------------------------------------------------------------------: | :--------------------------------------------------------------------: | | `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 | ✅ | ✅ | ✅ | ✅ | ❌ | | `AnyChange` | All | 0 | ❌ | ✅ | ✅ | ❌ | ❌ | | `PercentChange` | number | 0 | ❌ | ✅ | ✅ | ❌ | ❌ | --- # AdaptableQL Predicate Technical Reference Canonical page: https://www.adaptabletools.com/docs/adaptable-predicate-technical-reference - The Predicate Options section in Adaptable Options contains many properties to configure Predicates - The Predicate API section of AdapTable API provides run-time access to Predicates --------- ## Predicate Options The [`Predicate Options`](https://www.adaptabletools.com/docs/reference/predicateoptions.md) section of Adaptable Options provides options for managing [Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md). This includes Custom Predicate Definitions and a set of functions which limit which System Predicates are available. | Property | Type | Description | Default | | --- | --- | --- | --- | | [caseSensitivePredicates](https://www.adaptabletools.com/docs/reference/predicateoptions.md#casesensitivepredicates) | `boolean \| ((context: `[`AdaptableColumnContext`](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md)`) => boolean)` | Perform case-sensitive text comparisons when evaluating Predicates | false | | [customPredicateDefs](https://www.adaptabletools.com/docs/reference/predicateoptions.md#custompredicatedefs) | `(`[`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md)` \| AdaptablePredicateDefPartialWithExtends)[]` | Definitions for Custom provided Predicates | [] | | [evaluateInPredicateUsingTime](https://www.adaptabletools.com/docs/reference/predicateoptions.md#evaluateinpredicateusingtime) | `boolean \| ((context: `[`AdaptableColumnContext`](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md)`) => boolean)` | Should In Predicate evaluate using datetime, rather than date (the default) | false | | [systemAlertPredicates](https://www.adaptabletools.com/docs/reference/predicateoptions.md#systemalertpredicates) | [`SystemAlertPredicateIds`](https://www.adaptabletools.com/docs/reference/systemalertpredicateids.md)` \| ((context: `[`SystemPredicatesContext`](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md)`<`[`SystemAlertPredicateId`](https://www.adaptabletools.com/docs/reference/systemalertpredicateid.md)`>) => `[`SystemAlertPredicateIds`](https://www.adaptabletools.com/docs/reference/systemalertpredicateids.md)`)` | Which System Predicates are available in Alert Module | all `SystemAlertPredicateIds` | | [systemFilterPredicates](https://www.adaptabletools.com/docs/reference/predicateoptions.md#systemfilterpredicates) | [`SystemFilterPredicateIds`](https://www.adaptabletools.com/docs/reference/systemfilterpredicateids.md)` \| ((context: `[`SystemPredicatesContext`](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md)`<`[`SystemFilterPredicateId`](https://www.adaptabletools.com/docs/reference/systemfilterpredicateid.md)`>) => `[`SystemFilterPredicateIds`](https://www.adaptabletools.com/docs/reference/systemfilterpredicateids.md)`)` | Which System Predicates are available when Filtering | all `SystemFilterPredicateIds` | | [systemFlashingCellPredicates](https://www.adaptabletools.com/docs/reference/predicateoptions.md#systemflashingcellpredicates) | [`SystemFlashingCellPredicateIds`](https://www.adaptabletools.com/docs/reference/systemflashingcellpredicateids.md)` \| ((context: `[`SystemPredicatesContext`](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md)`<`[`SystemFlashingCellPredicateId`](https://www.adaptabletools.com/docs/reference/systemflashingcellpredicateid.md)`>) => `[`SystemFlashingCellPredicateIds`](https://www.adaptabletools.com/docs/reference/systemflashingcellpredicateids.md)`)` | Which System Predicates are available in Flashing Cell Module | all `SystemFlashingCellPredicateIds` | | [systemFormatColumnPredicates](https://www.adaptabletools.com/docs/reference/predicateoptions.md#systemformatcolumnpredicates) | [`SystemFormatColumnPredicateIds`](https://www.adaptabletools.com/docs/reference/systemformatcolumnpredicateids.md)` \| ((context: `[`SystemPredicatesContext`](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md)`<`[`SystemFormatColumnPredicateId`](https://www.adaptabletools.com/docs/reference/systemformatcolumnpredicateid.md)`>) => `[`SystemFormatColumnPredicateIds`](https://www.adaptabletools.com/docs/reference/systemformatcolumnpredicateids.md)`)` | Which System Predicates are available in Format Column Module | all `SystemFormatColumnPredicateIds` | --------- ## Predicate API The [`Predicate API`](https://www.adaptabletools.com/docs/reference/predicateapi.md) section of Adaptable API provides run-time access to Predicates: | Method | Returns | Description | | --- | --- | --- | | [getCustomPredicateDefById(predicateId)](https://www.adaptabletools.com/docs/reference/predicateapi.md#getcustompredicatedefbyid) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md) | Gets Predicate Definition provided by users for given Id | | [getCustomPredicateDefs()](https://www.adaptabletools.com/docs/reference/predicateapi.md#getcustompredicatedefs) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md)`[]` | Returns Predicate Definitions provided by users | | [getPredicateDefById(predicateId)](https://www.adaptabletools.com/docs/reference/predicateapi.md#getpredicatedefbyid) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md) | Gets the Predicate Definition for a given Id | | [getPredicateDefs()](https://www.adaptabletools.com/docs/reference/predicateapi.md#getpredicatedefs) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md)`[]` | Returns all current Predicate Definitions | | [getPredicateDefsByModuleScope(moduleScope)](https://www.adaptabletools.com/docs/reference/predicateapi.md#getpredicatedefsbymodulescope) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md)`[]` | Retrieves all Predicate Definitions for given Module Scope | | [getSystemPredicateDefById(predicateId)](https://www.adaptabletools.com/docs/reference/predicateapi.md#getsystempredicatedefbyid) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md) | Gets Predicate Definition provided by AdapTable for given Id | | [getSystemPredicateDefs()](https://www.adaptabletools.com/docs/reference/predicateapi.md#getsystempredicatedefs) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md)`[]` | Returns Predicate Definitions provided by AdapTable | | [getSystemPredicateDefsByModuleScope(moduleScope)](https://www.adaptabletools.com/docs/reference/predicateapi.md#getsystempredicatedefsbymodulescope) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md)`[]` | Returns Predicate Definitions provided by AdapTable for given Module Scope | | [handleColumnPredicate(predicate, params, defaultReturn)](https://www.adaptabletools.com/docs/reference/predicateapi.md#handlecolumnpredicate) | `boolean` | Same has handle predicate but it tales into account predicate column id. | | [handleColumnPredicates(predicate, params, defaultReturn)](https://www.adaptabletools.com/docs/reference/predicateapi.md#handlecolumnpredicates) | `boolean` | Same has handle predicates but it tales into account predicate column id. | | [handlePredicate(predicate, params, defaultReturn)](https://www.adaptabletools.com/docs/reference/predicateapi.md#handlepredicate) | `boolean` | Main Handler function for a Predicate Definition - used by AdapTableQL | | [handlePredicates(predicates, params, defaultReturn)](https://www.adaptabletools.com/docs/reference/predicateapi.md#handlepredicates) | `boolean` | Handle and compose (with AND) the given Predicate Definitions | | [isEveryPredicateValid(predicates)](https://www.adaptabletools.com/docs/reference/predicateapi.md#iseverypredicatevalid) | `boolean` | Checks if all predicates are valid | | [isValidPredicate(predicate)](https://www.adaptabletools.com/docs/reference/predicateapi.md#isvalidpredicate) | `boolean` | Checks whether a given Predicate Definition is valid | | [predicatesToString(predicates, logicalOperator)](https://www.adaptabletools.com/docs/reference/predicateapi.md#predicatestostring) | `string` | Stringifies a list of Predicate Definitions, using the given logical operator (AND/OR) | | [predicateToString(predicate)](https://www.adaptabletools.com/docs/reference/predicateapi.md#predicatetostring) | `string` | Stringifies a given Predicate Definition | | [useCaseSensitivity(columnId)](https://www.adaptabletools.com/docs/reference/predicateapi.md#usecasesensitivity) | `boolean` | Whether Predicates are evaluated using Case Sensitivity | --- # Guide to Expressions in AdapTableQL Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression - AdapTableQL is an advanced, custom Query Language developed by the AdapTable Tools team - It evaluates and executes complex queries (called **Expressions**) defined at design or run time - AdapTableQL is designed and implemented to be fast, efficient and highly performant - It is also designed with the requirement to operate with large data sets in mind - Expressions are commonly used whenever data needs to be searched, filtered, watched, derived or evaluated - Expression can be hand-written or created in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) - an advanced UI tool designed for this purpose - There are 3 main types of Expressions available in AdapTable: - `Standard` - Evaluates of each row in isolation - `Aggregated` - Evaluates data over a set of rows (with specialised `Cumulative` and `Quantile` aggregations) - `Observable` - A Reactive Expression used to watch data changes over time AdapTableQL is a powerful, home-grown, Query Language designed by the AdapTable Tools team. AdapTableQL includes a powerful rules engine used for evaluating live data. - AdapTable also provides [Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) which are designed for more basic use cases - They are an entirely different way to query data in AdapTable than Expressions - 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 ## Expressions At the heart of AdapTableQL are **Expressions** - a very powerful querying construct which: - Can contain numerous functions, conditions and arguments - Are typically evaluated against whole rows of AG Grid data - Can support multiple return types - Includes reactive(observable), aggregated or cumulated expressions - Are designed to be fully human-readable and can be written entirely by hand - Expressions 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 There are 3 main types of Expressions provided by AdapTableQL: | Type | Returns | Modules | | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Standard](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) | Single value of any type | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) (Boolean)

[Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) (Any)

[Export](https://www.adaptabletools.com/docs/handbook-exporting/index.md) (Boolean)

[Flashing Cell](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) (Boolean)

[Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) (Boolean)

[Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) (Boolean)

[Plus Minus](https://www.adaptabletools.com/docs/handbook-editing-plus-minus/index.md) (Boolean) | | [Aggregation](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) | Single value (calculated across aggregated cells) - also includes specialist [Cumulative](https://www.adaptabletools.com/docs/adaptable-ql-expression-cumulative/index.md) and [Quantile](https://www.adaptabletools.com/docs/adaptable-ql-expression-quantile/index.md) Aggregations | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) (Boolean)

[Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) (Any, Quantile, Cumulative) | | [Observable](https://www.adaptabletools.com/docs/adaptable-ql-expression-observable/index.md) | Details of any Row or Grid Changes | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) | ### Standard A Standard Expression is evaluated **against each row** in isolation and returns a single value. Standard (particularly Boolean) Expressions are the most common type of Expression used in AdapTable The return value can be of 2 return types: - **any** data type - used in the [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) Module - **boolean** data type - used when a true / false condition needs to be evaluated, e.g. [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) Module only displays rows, and [Conditional Styling](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) only styles rows, where the evaluated Expression returns true. - See [Standard Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) for examples and more information - Consult the full list of available [Standard Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) ### Aggregated Aggregated Expressions are run against **aggregated data**; each value is dynamically derived by aggregating multiple rows and columns of the grid. There are 4 types of Aggregated Expression : - Aggregated Scalar - return value of any data type and available when creating [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md). - Aggregated Boolean Expressions: return true / false currently used in the [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) Module. - This is ideal for Limits Management and related scenarios - You can check that a sum comprising multiple cell values has not been exceeded - Cumulative Expressions - Perform Cumulative Aggregations - Quantile Expressions - Create 'buckets' of values - See [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) for examples and more information - Consult the full list of available [Aggregation Boolean](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md#aggregatedboolean-functions) and [Aggregation Scalar](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md#aggregated-scalar-functions) Expression Functions ### Observable (Rx) Observable Expressions use advanced __reactive techniques (Rx)__ to watch for changes (or lack of changes) in data that match a particular pattern. When the expression evaluates to `TRUE`, AdapTable can perform a specified action. Currently only [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) supports Observable Expressions, but this will be extended to other Modules - See [Observable (Rx) Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-observable/index.md) for examples and more information - Check out the [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) Module for real use cases of Observable Expressions - Consult the full list of available [Observable (Rx) Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md#observable-functions) ## Expression Modules AdapTable users are able to use Expressions in numerous [Modules](https://www.adaptabletools.com/docs/technical-reference-adaptable-modules/index.md). Some Adaptable Module may reference more than one type of Expression | Module | Type | Usage | | -------------------------------------------------------------------------- | ---------- | ---------------------------------------------------------- | | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) | Standard | Triggers an Alert when data change matches a Rule | | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) | Observable | Triggers an Alert based on observed criteria | | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) | Aggregated | Triggers an Alert using aggregation functions | | [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) | Standard | Expression is evaluated for each cell in the column | | [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) | Aggregated | Expression is evaluated by aggregating multiple grid cells | | [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) | Cumulative | Performs Cumulative Aggregations | | [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) | Quantile | Creates 'buckets' of values | | [Export](https://www.adaptabletools.com/docs/handbook-exporting/index.md) | Standard | Custom Reports only exports rows returned by Query | | [Flashing Cell](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) | Standard | Whether the Cell should flash when its value changes | | [Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) | Standard | Sets whether or not to show the Format Column | | [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) | Standard | Returns rows which match the true / false condition | | [Plus Minus](https://www.adaptabletools.com/docs/handbook-editing-plus-minus/index.md) | Standard | Manages evaluation of Custom Nudge Values | ## Expression Functions An Expression will include (potentially multiple) **Expression Functions**. These are useful functions that are shipped with AdapTableQL which cover a multitude of use cases. Developers are able to provide [Custom Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom/index.md) if required There are 3 types of Expression function available in AdapTableQl - in line with the 3 types of Expressions: | Type | Description | Available in Expressions | | -------------------------------------------------------------------------------------- | --------------------------------------- | --------------------------------- | | [Standard](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-standard/index.md) | Returns single value of any return type | Standard, Observable, Aggregation | | [Observable](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-observable/index.md) | Watches for Changes | Observable | | [Aggregation](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-aggregated/index.md) | Returns single value of any return type | Aggregation | For example this Standard Expression contains 3 Expression Functions: ```ts [[1, 1, "STARTS_WITH"], [2, 1, "OR"], [3, 1, "MIN"]] STARTS_WITH([col1], 'ABC') OR MIN([col2], [col3]) > 100 ``` - `STARTS_WITH` Boolean Expression Function - `OR` Logical Function - `MIN` Scalar Expression Function Consult the [AdapTableQL Expression List](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) for full details of all the Expression Functions available in AdapTableQL ### Advanced Expression Functions AdapTableQL provides some "specialised" Functions for particular, advanced use cases: - `QUERY` Function - enables referencing [Named Queries](https://www.adaptabletools.com/docs/handbook-named-queries/index.md) in other Expressions A Named Query is a Boolean Expression that has been named and saved into Query State for subsequent re-use - `VAR` Function - allows developers to provide values which will be evaluated in other Expressions - `CASE` and `Ternary` Operators - enable logic to be used inside Expressions See [Advanced Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced/index.md) for full details on all of these functions ## Writing Expressions Expressions are designed to be hand-written and human readable. An Expression can include many different elements including: - Expression Functions - Operators - Columns - Hard coded values Expression can contain as many of each of these elements as are required See [Standard Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) for in-depth instructions on creating Expressions ### UI Components AdapTableQL is designed to be used at run time by end users with no technical expertise. AdapTable provides 2 very useful **UI Components** designed to add easy creation of Expressions: - [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md) enables (Boolean) Expressions to be created purely via UI controls - [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) used to hand-write Expressions (and for more complicated scenarios), and contains many useful features including functions list, context help and validation See [Standard Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-ui/index.md) for more information ## Configuring Expressions Many elements in AdapTableQL can be configured using properties in [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md). In particular developers are able to: - add Custom Expression Functions - ensure that some Expression Functions are unavailable (both to end-users or to AdapTableQL) - reduce complexity - useful when evaluating expressions externally - configure case sensitivity ### Custom AdapTableQL Functions Developers can provide their own custom built ExpressionFunctions in [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md). Once provided, these Expressions will be available in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) and invoked by AdapTableQL when the Expression is being evaluated. See the [Guide to Providing Custom Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom/index.md) for full instructions ### Reducing Expression Complexity By default, all [System Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) are available to end users, and can be used against all columns. However sometimes developers might wish to reduce the AdapTableQL functionality on offer. This is often the case if you are evaluating Expressions yourself externally instead of using AdapTableQL In this scenario, AdapTable provides 2 features to help developers - namely: - [Remove some AdapTableQL functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-managing/index.md#limiting-available-adaptableql-functions) (either globally or on a per-module basis), so they are not available in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) - Specify that certain Columns cannot be queried or included in Expressions See [Reducing Expression Complexity](https://www.adaptabletools.com/docs/adaptable-ql-expression-managing/index.md) for further information ### Evaluating Expressions Externally Generally there is no need for developers to understand how AdapTableQL works; merely to ensure that it is provided with valid input. However, occasionally you might want [to perform some querying externally](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md) (e.g. on your Server). - This use case can occur even when using AG Grid's [Client Side Row Model](https://www.ag-grid.com/javascript-data-grid/client-side-model/#client-side-row-model) - This is different to using [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) which forces external evaluation and contains a different workflow This is possible and requires 3 steps: 1. In [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md) specify which modules should be evaluated externally (instead of AdapTableQL) 2. Listen to the [Grid Filter Applied Event](https://www.adaptabletools.com/docs/handbook-grid-filter-technical-reference/index.md) to know when Queries need to run 3. Perform the Query yourself and return the data to Adaptable - To help with this scenario, AdapTable makes available the **AST** which AdapTableQL uses for the Expression - This Abstract Syntax Tree can be accessed via functions in [Expression API](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md) The [Server Evaluation Guide](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md) provides full details on external Expression evaluation ### Case Sensitivity By default Expressions are **case insensitive** but this can be changed if required, by setting the `caseSensitiveExpressions` flag to *true*. ### `caseSensitiveExpressions` Keep case sensitivity when AdapTableQL evaluates string-based Expressions By default AdapTableQL will ignore case in its evaluations. Set this property to *true* to enforce case sensitivity. ```ts {4} // Enforce case sensitivity in AdapTable QL for string evaluations const adaptableOptions: AdaptableOptions = { expressionOptions: { caseSensitiveExpressions: true } } ``` --- # Advanced Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced - Expressions in AdapTable have some powerful features for more advanced use cases. These include: - Using `QUERY` to reference other Expressions by keyword - The `VAR` function which allows developers to provide values which can be evaluated in other Expressions - Complex Logic - using `IF` and `CASE` functions - Referencing row data (rather than Columns) inside Expressions Most Expressions are often fairly straightforward - typically just a couple of operands and an operator. However, Expressions can include more complex elements to deal with advanced use cases. This section of the documentation details some advanced Expression capabilities supported by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md): - [QUERY function](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-query-function/index.md) enables Named Queries to be referenced in an Expression - [VAR function](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-var-function/index.md) supports custom values which can be used in Expressions - [Support for Logic constructs](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-logic/index.md) - ternary operator and CASE statements facilitate using logic in Expressions - [Data in row fields](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-row-data/index.md) can be referenced (i.e. data that is not stored in Columns) - Another advanced Expression use case is [Custom Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom/index.md) - These allow developers to provide bespoke functions which are then invoked and evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) --- # Logic in Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-logic - AdaptableQL supports Logic in Expressions - this comes in 2 formats: - `IF` - uses a ternary operator - `CASE` statements (designed when using multiple clauses) Expressions can also include custom Logic. This can be provided in 2 ways: - via ternary logic (essentially an IF function) - using CASE Statements ## `IF` Function Expressions can include conditional logic via the IF function. This wraps a **ternary operator** (which uses the `?` sign) and is used for writing conditional expressions. It is used in Logical Expressions and is made up of 3 parts 1. a Boolean Expression to evaluate followed by a question mark (`?`) 2. the return value if the expression is true, followed by a colon (`:`) 3. the return value if the Expression is false ```ts [[1, 2, "[Comments] > 100 "], [2, 2, "Big"], [3, 2, "Small"]] // Return 'Big' if more than 100 Comments, otherwise 'Small' [Comments] > 100 ? 'Big' : 'Small' ``` There is no limit on the number of Ternary Operators in an Expression - which enables multiple conditions: ```ts [[1, 2, "[Comments] > 100 "], [2, 2, "Big"], [3, 2, "[Comments] > 50 "], [4, 2, "Medium"], [5, 2, "Small"]] // Return 'Big' if more than 100 Comments, 'Medium' if more than 50, otherwise 'Small' [Comments] > 100 ? 'Big' : [Comments] > 50 ? 'Medium' : 'Small' ``` **Example: Expression Logic: IF Function** Using Ternary Operator in Expressions - This demo contains a Calculated Column which is evaluated using Ternary Logic - `Popularity` examines the number of stars in `Github Stars` and returns an appropriate string value using the following logic: - Greater than 100,000 - "Very Popular" - Greater than 30,000 - "Popular" - Others - "Trending" ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Ternary Logic', initialState: { Dashboard: { ModuleButtons: ['CalculatedColumn', 'SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout', 'CalculatedColumn'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_watchers', 'github_stars', 'popularity', 'license', '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, }, ], }, CalculatedColumn: { CalculatedColumns: [ { FriendlyName: 'Popularity', ColumnId: 'popularity', Query: { ScalarExpression: '[github_stars] > 100000 ? "Very Popular" : [github_stars] > 30000 ? "Popular" : "Trending"', }, CalculatedColumnSettings: { DataType: 'text', }, }, ], }, }, }; ``` ## CASE Statements Sometimes the logic required in an Expression will make the Ternary Operator feel verbose or unsuitable. For this reason, AdapTableQL also offers switch-type logic common in many languages. It is provided by `CASE` statements which take this form: ```ts CASE [case_value] WHEN when_value THEN statement_list [WHEN when_value THEN statement_list] ... [ELSE statement_list] END ``` As can be seen they are made up of (up to) 4 parts: 1. `CASE` keyword followed - optionally - by the value being evaluated 2. Any number of conditions which each take the form `WHEN` x `THEN` y 3. A final, optional, `ELSE` to return the value if no conditions are met 4. An `END` statement which wraps up the section ```ts [[1, 1, "CASE [day]"], [2, 1, "WHEN 'Saturday' THEN 'weekend'"], [3, 1, "ELSE 'workday'"], [4, 1, "END"]] CASE [day] WHEN 'Saturday' THEN 'weekend' WHEN 'Sunday' THEN 'weekend' ELSE 'workday' END ``` As noted, the initial evaluation after CASE is optional and can be omitted: ```ts [[1, 1, "CASE"], [2, 1, "WHEN [price] < 10 THEN 'low'"], [3, 1, "ELSE 'high'"], [4, 1, "END"]] CASE WHEN [price] < 10 THEN 'low' WHEN [price] < 50 THEN 'medium' ELSE 'high' END ``` **Example: Expression Logic: Case Statements** Using Case Statements in Expressions - This demo contains 2 Calculated Columns which are evaluated using Case Statements - `Popularity` examines the number of stars in `Github Stars` and returns an appropriate string value using the following logic: - Greater than 100,000 - "Very High" - Greater than 40,000 - "Quite High" - Greater than 20,000 - "Low" - Else - "None" - `File` returns the correct file type for the `Language` column using the following logic: - `JavaScript` - ".js" - `TypeScript` - ".ts" - Else - ".html" ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Case Logic', initialState: { Dashboard: { ModuleButtons: ['CalculatedColumn', 'SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout', 'CalculatedColumn'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'file', 'github_stars', 'popularity', 'license', '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, }, ], }, CalculatedColumn: { CalculatedColumns: [ { FriendlyName: 'Popularity', ColumnId: 'popularity', Query: { ScalarExpression: "CASE WHEN [github_stars] > 100000 THEN 'Very High' WHEN [github_stars] > 40000 THEN 'Quite High' WHEN [github_stars] > 20000 THEN 'Low' ELSE 'None' END", }, CalculatedColumnSettings: { DataType: 'text', Resizable: true, Filterable: true, }, }, { FriendlyName: 'File', ColumnId: 'file', Query: { ScalarExpression: "CASE [language] WHEN 'JavaScript' THEN '.js' WHEN 'TypeScript' THEN '.ts' ELSE '.html' END", }, CalculatedColumnSettings: { DataType: 'text', Resizable: true, Filterable: true, }, }, ], }, }, }; ``` --- # QUERY Function Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-query-function - The `QUERY` Expression Function in AdaptableQL supports referencing Named Queries in Expressions The `QUERY` Expression Function enables referencing [Named Queries](https://www.adaptabletools.com/docs/handbook-named-queries/index.md) inside Expressions. A Named Query is a Boolean Expression that has been named and saved into Query State for subsequent re-use The referenced Query is identified by its name and it is evaluated on the fly by AdapTableQL. So the Expression below could be saved as a `Named Query` called 'Big Orders' ```ts [ItemCount] > 30 OR [OrderCost] > 500 ``` And this Named Query can now be referenced as follows: ```ts [[1, 1, "QUERY"]] QUERY("Big Orders") AND [Currency] = 'USD' ``` **Example: AdapTableQL: QUERY Expression Function** Using QUERY to reference other Expressions - This Example demonstrates how to use the `QUERY` Expression Function - A [Named Query](https://www.adaptabletools.com/docs/handbook-named-queries/index.md) is provided called 'Popular Frameworks' with the Expression: `[github_watchers] > 2000 OR [github_stars] > 14500` - This Named Query is then referenced in 3 places (using the `QUERY` keyword): - A [Custom Report](https://www.adaptabletools.com/docs/handbook-exporting/index.md) has the Expression: `QUERY("Popular Frameworks")` - A [Format Column Condition](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) has the Expression: `QUERY("Popular Frameworks") AND [has_wiki]` - A [Row Change Alert](https://www.adaptabletools.com/docs/handbook-alerting-row-change/index.md) has the Expression: `QUERY("Popular Frameworks") AND [language]="JavaScript"` - Edit the Named Query (through the Query Section in [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md)) and see how the Style changes - Change Has Wiki in rows with JavaScript and see the Alert appear; do the same in rows with TypeScript and not there is no Alert ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'QUERY Expression Function', initialState: { Dashboard: { ModuleButtons: ['FormatColumn', 'SettingsPanel'], Tabs: [ { Name: 'Expressions', Toolbars: ['Alert', 'Export', 'GridFilter'], }, ], }, Theme: {CurrentTheme: 'dark'}, NamedQuery: { NamedQueries: [ { Name: 'Popular Frameworks', BooleanExpression: '[github_watchers] > 2000 OR [github_stars] > 14500', }, ], }, Alert: { AlertDefinitions: [ { Name: 'alert-frameworks-javascript', Scope: { All: true, }, MessageType: 'Warning', Rule: { BooleanExpression: 'QUERY("Popular Frameworks") AND [language]="JavaScript" ', }, AlertProperties: { DisplayNotification: true, }, }, ], }, Export: { Reports: [ { Name: 'Popular', ReportColumnScope: 'AllColumns', ReportRowScope: 'ExpressionRows', Query: { BooleanExpression: 'QUERY("Popular Frameworks")', }, }, ], CurrentReport: 'Popular', }, FormatColumn: { FormatColumns: [ { Name: 'style-frameworks-wiki', Scope: {All: true}, Rule: { BooleanExpression: 'QUERY("Popular Frameworks") AND [has_wiki]', }, Style: { ForeColor: 'White', BackColor: 'Brown', }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard 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', ], AutoSizeColumns: true, }, ], }, }, }; ``` See [Named Queries](https://www.adaptabletools.com/docs/handbook-named-queries/index.md) for more information and an accompanying demo --- # Referencing Row Data in Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-row-data - AdaptableQL can reference data that is in the data source but is not a Column - This is done via the FIELD expression function - Fields are defined in Expression Options Expressions typically directly reference data which is stored in an [Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md). However Expressions can also operate on row data which is **not** contained in a Column. The data for the field needs to be in the underlying data source but its not represented by an AG Grid Column This is done via 2 stage process: - **define** the Fields in the `fields` property of [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md) (so they are available in the UI) - **reference** the Fields in Expressions by using the `FIELD` keyword ## Defining Fields Fields are defined by being listed in the `fields` property of [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md). This means the Fields are now **available in the AdapTableQL UI** and can be used similarly to Columns: - The [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md) allows users to select Fields when creating Conditions - similar to Columns - The [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) lists all defined Fields which are draggable into the Editor - Expressions containing Fields that have not been defined in Expression Options are still perfectly valid - However the Expression cannot be edited in Query Builder The Fields can be provided either as a list or via a function which returns a list. ### `fields` Non-column row data to be used in AdapTableQL Expressions [`AdaptableField[]`](https://www.adaptabletools.com/docs/reference/adaptablefield.md) This property returns a list of row data fields which can be used in AdapTableQL Expressions even though they are not AG Grid Columns. ```ts fields?: AdaptableField[] | ((context: AdaptableFieldContext) => AdaptableField[]); ``` The [`AdaptableField`](https://www.adaptabletools.com/docs/reference/adaptablefield.md) object is defined as follows: | Property | Type | Description | | --- | --- | --- | | [dataType](https://www.adaptabletools.com/docs/reference/adaptablefield.md#datatype) | [`AdaptableColumnDataType`](https://www.adaptabletools.com/docs/reference/adaptablecolumndatatype.md) | Data Type of field, used to validate and show correctly in UI | | [label](https://www.adaptabletools.com/docs/reference/adaptablefield.md#label) | `string` | Label for field (optional - defaults to name) | | [name](https://www.adaptabletools.com/docs/reference/adaptablefield.md#name) | `string` | Name of field in data source, e.g. 'rowId', 'parentObject.childObject.value' | The `label` property is optional - if not provided the `name` property is used Providing a List The easiest way to provide fields is via a list: ```ts {3} // Provide 2 fields - one of which is nested expressionOptions:{ fields: [ { label: 'Forks', name: 'forks_count', dataType: 'number', }, { label: 'Watchers Multiplier', name: 'multipliers.watchers_multiplier', dataType: 'number', }, ]}; ``` Using a Function Alternatively you can provide a function which will return the list. The function receives [`AdaptableFieldContext`](https://www.adaptabletools.com/docs/reference/adaptablefieldcontext.md) object which simply wraps `BaseContext` and 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 | ## Referencing Fields Fields are referenced in [Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) using the `FIELD` keyword. This has a single parameter which is the `name` of the data field: ```ts [[1, 1, "FIELD"], [2, 1, "forks_count"]] FIELD('forks_count') ``` When using Fields you **have** to use the `FIELD` keyword explicitly - the square brackets shortcut is not available ### Nested Row Data If the row data is nested inside another object, you need to use the full reference using the '.' operator. For instance if a `multipliers` object contained a `watchers_multiplier` property, it should be referenced: ```ts [[1, 1, "FIELD"], [2, 1, "multipliers"], [3, 1, "."], [4, 1, "watchers_multiplier"]] FIELD('multipliers.watchers_multiplier') ``` **Example: Expressions using Row Data** Using non Column Row Data in Expressions - This example shows how to create AdapTableQL Expressions that reference **row data**, rather than Columns - We added 3 additional fields to our typical row data: `forks_count`, `stars_multiplier` & `watchers_multiplier` (the latter 2 inside a nested `multipliers` object) - We then defined those fields in the `fields` property of [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md) (so they are available in the UI) - We wrote Expressions that reference this row data using the `FIELD` property (even though neither are Columns): - 2 [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - `Full Stars` and `Full Watchers` that multiply `Github Stars` and `Github Watchers` with their respective multiplier values - A [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) with the simple Expression: `FIELD('forks_count') > 5000` - We also applied a [Custom Sort](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md) to `Github Stars` (that multiplies by `stars_multiplier`) - which is why the Column doesn't sort numerically ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {IRowNode} from 'ag-grid-enterprise'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Referencing Row Data', expressionOptions: { fields: [ { label: 'Forks', name: 'forks_count', dataType: 'number', }, { label: 'Stars Multiplier', name: 'multipliers.stars_multiplier', dataType: 'number', }, { label: 'Watchers Multiplier', name: 'multipliers.watchers_multiplier', dataType: 'number', }, ], }, customSortOptions: { customSortComparers: [ { name: 'Comparer-github_stars', scope: { ColumnIds: ['github_stars'], }, comparer: ( valueA: any, valueB: any, nodeA: IRowNode | undefined, nodeB: IRowNode | undefined ) => { const nodeAnodeAStarsMultiplier = nodeA?.data['multipliers.stars_multiplier'] * valueA; const nodeBStarsMultiplier = nodeB?.data['multipliers.stars_multiplier'] * valueB; if (nodeAnodeAStarsMultiplier > nodeBStarsMultiplier) { return -1; } if (nodeAnodeAStarsMultiplier < nodeBStarsMultiplier) { return 1; } return 0; }, }, ], }, initialState: { Dashboard: { PinnedToolbars: ['GridFilter'], ModuleButtons: ['CalculatedColumn', 'SettingsPanel'], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'full_stars', 'github_watchers', 'full_watchers', 'license', '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', ], ColumnSorts: [ { ColumnId: 'github_stars', SortOrder: 'Asc', }, ], Name: 'Standard Layout', GridFilter: { Expression: "FIELD('forks_count') > 5000", }, AutoSizeColumns: true, }, ], }, CalculatedColumn: { CalculatedColumns: [ { FriendlyName: 'Full Stars', ColumnId: 'full_stars', Query: { ScalarExpression: "[github_stars] * FIELD('multipliers.stars_multiplier')", }, CalculatedColumnSettings: { DataType: 'number', Resizable: true, Filterable: true, }, }, { FriendlyName: 'Full Watchers', ColumnId: 'full_watchers', Query: { ScalarExpression: "[github_watchers] * FIELD('multipliers.watchers_multiplier')", }, CalculatedColumnSettings: { DataType: 'number', Resizable: true, Filterable: 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; 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; // These fields will not be columns forks_count?: number; multipliers?: {stars_multiplier?: number; watchers_multiplier?: 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', 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, forks_count: 36403, multipliers: {stars_multiplier: 5, watchers_multiplier: 2}, }, { 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', 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, forks_count: 20569, multipliers: {stars_multiplier: 3, watchers_multiplier: 3}, }, { 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', 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, forks_count: 30945, multipliers: {stars_multiplier: 3, watchers_multiplier: 4}, }, { 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', 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, forks_count: 2584, multipliers: {stars_multiplier: 1, watchers_multiplier: 3}, }, { 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, multipliers: {stars_multiplier: 3, watchers_multiplier: 2}, }, { 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', 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, forks_count: 528, multipliers: {stars_multiplier: 3, watchers_multiplier: 2}, }, { 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', 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, forks_count: 316, multipliers: {stars_multiplier: 5, watchers_multiplier: 2}, }, { 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', 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, forks_count: 4253, multipliers: {stars_multiplier: 5, watchers_multiplier: 2}, }, { 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', 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, forks_count: 641, multipliers: {stars_multiplier: 2, watchers_multiplier: 3}, }, { 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', 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, forks_count: 330, multipliers: {stars_multiplier: 4, watchers_multiplier: 2}, }, { 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, multipliers: {stars_multiplier: 1, watchers_multiplier: 2}, }, { 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, multipliers: {stars_multiplier: 2, watchers_multiplier: 4}, }, { 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, multipliers: {stars_multiplier: 5, watchers_multiplier: 4}, }, { 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, multipliers: {stars_multiplier: 3, watchers_multiplier: 3}, }, { 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, multipliers: {stars_multiplier: 3, watchers_multiplier: 2}, }, { 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, multipliers: {stars_multiplier: 4, watchers_multiplier: 2}, }, { 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, multipliers: {stars_multiplier: 2, watchers_multiplier: 3}, }, { 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: 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, multipliers: {stars_multiplier: 5, watchers_multiplier: 4}, }, { 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, multipliers: {stars_multiplier: 3, watchers_multiplier: 1}, }, { 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, multipliers: {stars_multiplier: 15, watchers_multiplier: 2}, }, { 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: 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, multipliers: {stars_multiplier: 3, watchers_multiplier: 2}, }, { 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, multipliers: {stars_multiplier: 5, watchers_multiplier: 2}, }, { 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, multipliers: {stars_multiplier: 5, watchers_multiplier: 3}, }, { 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, multipliers: {stars_multiplier: 20, watchers_multiplier: 2}, }, { 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, multipliers: {stars_multiplier: 4, watchers_multiplier: 5}, }, ]; ``` --- # VAR Function Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-var-function - The `VAR` function in AdaptableQL enables developers to supply bespoke, custom values - These can then be referenced, and evaluated, in other Expressions The `VAR` Expression Function allows developers to provide custom values which can be used in Expressions. The return value of the `VAR` can be either - a 'hard-coded' value (string, number, boolean or Date) - a function that returns a value The VAR values are provided at design-time via the `customQueryVariables` property in [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md). ### `customQueryVariables` Custom variables to be used in AdapTableQL Property which allow values to be attached to variables so that a single value can easily be expressed multiple times within a query, or quickly changed to affect the results of a query. Variables are evaluated synchronously with each expression evaluation. The definition of the property is: ```ts customQueryVariables?: Record< string, | string | number | boolean | Date | ((context: CustomQueryVariableContext) => string | number | boolean | Date) ``` As can be seen you can provide a Record of string (key) and either value or function that returns a value. So, for example, a VAR which returns the VAT rate can be provided in 2 ways. Either as a hard-coded value: ```ts {3,4} // Provide VAT as a hard-coded value expressionOptions:{ customQueryVariables: { VAT: 1.2, } }; ``` Or using a function which receives a `CustomQueryVariableContext` object and returns a value. The [`CustomQueryVariableContext`](https://www.adaptabletools.com/docs/reference/customqueryvariablecontext.md) contains the custom args required by the VAR. ```ts {3,4} // Provide VAT using a function (in the real world this will call server logic) expressionOptions:{ customQueryVariables: { VAT: (context: CustomQueryVariableContext) => { if (context.args) { const country: any = context?.args[0]; switch (country) { case 'US': return 1; case 'Japan': return 1.1; case 'Germany': return 1.19; case 'UK': return 1.2; } } return 1; }, }, }; ``` **Example: AdapTableQL: VAR Expression Function** Using VAR to provide placeholders and variables - This Example demonstrates how to use the `VAR` Expression Function - In [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md) we define 3 `VAR` Expressions (all of which are then used in Adaptable Objects): - `EMISSION_DATE` - has a hard-coded value of 1 Jan 2014 - and then used in a [Format Column Condition](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) - `VAT` - a function that returns a number based on the Country param it receives - used to create the `Full Price` [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - `BEST_SELLER` - has a mock server returned value of "Corolla" - and then used in a [Format Column Condition](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) and a [Data Change Alert](https://www.adaptabletools.com/docs/handbook-alerting-data-change/index.md) - We have also created a [Named Query](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) called 'Good Performance' which uses the first 2 VAR Expressions ### Expand to see how the VAR Expression Functions are Used The `VAR` Expression Functions are defined in Adaptable Options: ```ts expressionOptions: { customQueryVariables: { BEST_SELLER: () => { return 'Corolla'; // in reality would fetch from server }, EMISSION_DATE: new Date(2014, 0, 1), VAT: (context: CustomQueryVariableContext) => { if (context.args) { const country: any = context?.args[0]; switch (country) { case 'US': return 1; case 'Japan': return 1.1; case 'Germany': return 1.19; } } return 1; }, }, }, ``` and they are referenced in Initial Adaptable State: ```ts Alert: { AlertDefinitions: [ { Name: 'alert-best-seller', Scope: { All: true, }, Rule: { BooleanExpression: '[model] = VAR("BEST_SELLER")', }, MessageType: 'Warning', MessageText: 'Updating the current Best Seller!', AlertProperties: { DisplayNotification: true, }, }, ], NamedQuery: { NamedQueries: [ { Name: 'Good Performance', BooleanExpression: 'VAR("VAT",[country]) > 1 AND DIFF_YEARS(VAR("EMISSION_DATE") , [productionDate]) < 1', }, ], }, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'full_price', FriendlyName: 'Full Price', Query: { ScalarExpression: "[price] * VAR('VAT',[country])", }, CalculatedColumnSettings: { DataType: 'number', Resizable: true, }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'style-emissions', Style: { BackColor: '#b3e5fc', FontStyle: 'Italic', }, Scope: { All: true, }, Rule: { BooleanExpression: 'VAR("EMISSION_DATE") > [productionDate]', }, }, { Name: 'style-best-seller', Style: { FontSize: 'Large', FontWeight: 'Bold', FontStyle: 'Italic', }, Scope: { ColumnIds: ['model'], }, Rule: { BooleanExpression: 'VAR("BEST_SELLER") = [model]', }, }, ], }, ``` - Change the Price for "Corolla" and note the Alert that fires - Select and run the "Good Performance" Query from the Grid Filter Toolbar and see both VAR Expressions be used ```ts import { AdaptableOptions, CustomQueryVariableContext, } from '@adaptabletools/adaptable'; import {Car} from './rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'model', adaptableId: 'VAR Expression Functions', expressionOptions: { customQueryVariables: { BEST_SELLER: () => { return 'Corolla'; // would normally fetch from server }, EMISSION_DATE: new Date(2014, 0, 1), VAT: (context: CustomQueryVariableContext) => { if (context.args) { const country: any = context?.args[0]; switch (country) { case 'US': return 1; case 'Japan': return 1.1; case 'Germany': return 1.19; } } return 1; }, }, }, initialState: { Dashboard: { ModuleButtons: ['FormatColumn', 'SettingsPanel'], PinnedToolbars: ['GridFilter'], }, Theme: {CurrentTheme: 'dark'}, NamedQuery: { NamedQueries: [ { Name: 'Good Performance', BooleanExpression: 'VAR("VAT",[country]) > 1 AND DIFF_YEARS(VAR("EMISSION_DATE") , [productionDate]) < 1', }, ], }, Alert: { AlertDefinitions: [ { Name: 'alert-best-seller', Scope: { All: true, }, Rule: { BooleanExpression: '[model] = VAR("BEST_SELLER")', }, MessageType: 'Warning', MessageText: 'Updating the current Best Seller!', AlertProperties: { DisplayNotification: true, }, }, ], }, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'full_price', FriendlyName: 'Full Price', Query: { ScalarExpression: "[price] * VAR('VAT',[country])", }, CalculatedColumnSettings: { DataType: 'number', Resizable: true, }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'style-emissions', Style: { BackColor: '#b3e5fc', ForeColor: 'Black', }, Scope: { All: true, }, Rule: { BooleanExpression: 'VAR("EMISSION_DATE") > [productionDate]', }, }, { Name: 'style-best-seller', Style: { FontSize: 'Large', FontWeight: 'Bold', FontStyle: 'Italic', }, Scope: { ColumnIds: ['model'], }, Rule: { BooleanExpression: 'VAR("BEST_SELLER") = [model]', }, }, { Name: 'formatColumn-price-full_price', Scope: { ColumnIds: ['price', 'full_price'], }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { Prefix: '$', FractionDigits: 0, }, }, }, { Name: 'formatColumn-milesToGallon', Scope: { ColumnIds: ['milesToGallon'], }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { FractionDigits: 2, }, }, }, { Name: 'formatColumn-productionDate', Scope: { ColumnIds: ['productionDate'], }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'yyyy/MM/dd', }, }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'make', 'model', 'price', 'full_price', 'productionDate', 'available', 'milesToGallon', 'country', ], AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {GridOptions, themeBalham} from 'ag-grid-enterprise'; import {columnDefs} from './columnDefs'; import {Car, rowData} from './rowData'; 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 {ColDef} from 'ag-grid-enterprise'; import {Car} from './rowData'; export const columnDefs: ColDef[] = [ { headerName: 'Make', field: 'make', filter: true, editable: false, enableRowGroup: true, enablePivot: true, cellDataType: 'text', }, { headerName: 'Model', field: 'model', filter: true, editable: false, cellDataType: 'text', }, { headerName: 'Price', field: 'price', filter: true, editable: true, cellDataType: 'number', }, { headerName: 'Miles To Gallon', field: 'milesToGallon', filter: true, editable: false, cellDataType: 'number', }, { headerName: 'Produced', field: 'productionDate', filter: true, editable: false, cellDataType: 'date', }, { headerName: 'Available', field: 'available', filter: true, editable: true, cellDataType: 'boolean', }, { headerName: 'Country', field: 'country', filter: true, editable: false, cellDataType: 'text', }, ]; ``` ```ts export interface Car { make: string; model: string; price: number; productionDate: Date; available: boolean; milesToGallon: number; country: string; } export const rowData: Car[] = [ { make: 'Toyota', model: 'Camry', price: 35000, productionDate: new Date(2017, 11, 4), available: true, milesToGallon: 21.345676, country: 'Japan', }, { make: 'Toyota', model: 'Yaris', price: 40000, productionDate: new Date(2013, 1, 15), available: true, milesToGallon: 29.32432423, country: 'Japan', }, { make: 'Toyota', model: 'Corolla', price: 28000, productionDate: new Date(2017, 6, 9), available: false, milesToGallon: 32.9032523473287, country: 'Japan', }, { make: 'Ford', model: 'Mondeo', price: 32000, productionDate: new Date(2009, 10, 2), available: true, milesToGallon: 28.247893473289, country: 'US', }, { make: 'Ford', model: 'Fiesta', price: 35000, productionDate: new Date(2018, 8, 12), available: false, milesToGallon: 34.0001, country: 'US', }, { make: 'Ford', model: 'Focus', price: 26750, productionDate: new Date(2017, 3, 3), available: false, milesToGallon: 31.2432432423, country: 'US', }, { make: 'Ford', model: 'Galaxy', price: 41000, productionDate: new Date(2015, 4, 14), available: false, milesToGallon: 29.29432404, country: 'US', }, { make: 'Porsche', model: 'Boxter', price: 72500, productionDate: new Date(2016, 1, 28), available: true, milesToGallon: 32.29580292, country: 'Germany', }, { make: 'Porsche', model: 'Mission', price: 81000, productionDate: new Date(2008, 10, 7), available: false, milesToGallon: 35.7822957, country: 'Germany', }, { make: 'Mitsubbishi', model: 'Outlander', price: 97800, productionDate: new Date(2017, 11, 14), available: true, milesToGallon: 19.224309, country: 'Japan', }, ]; ``` --- # Aggregation Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation - Aggregated Expressions are evaluated against grouped data and can return any value - 3 specialised use cases are also available: - Limiting scope of Expression to a group of rows by using the `GROUP_BY` function - Performing cumulative aggregations by using the `CUMUL` and `OVER` functions - Creating buckets (e.g. Quartiles, Percentiles) using the `QUANT` function Aggregation Scalar Expressions are special [Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) which run against __aggregated data__. They can be of 2 types: | Type | Returns | Available in Modules | | ----------- | ------------- | -------------------------------------------------------------------------- | | **Scalar** | Any value | [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) | | **Boolean** | True or False | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) | AdapTable also provides 2 **specialist** Aggregation Scalar Expressions: [Cumulative](https://www.adaptabletools.com/docs/adaptable-ql-expression-cumulative/index.md) and [Quantile](https://www.adaptabletools.com/docs/adaptable-ql-expression-quantile/index.md) The Expression evaluates to a single value for each row, but each value is dynamically derived by aggregating multiple rows and columns of the grid. ## Scalar Aggregtion Expressions Scalar Aggregation Expressions are the most basic form of Aggregation. - By default Scalar Aggregated Expressions will compute against the whole grid - See [Grouped Aggregation](#grouped-aggregation) for more advanced used cases Scalar Aggregation Expressions are of type [`Aggregated Scalar Query`](https://www.adaptabletools.com/docs/reference/adaptableaggregatedscalarquery.md), and require just 2 elements: ### `` This is the [AdapTableQL Aggregated Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-aggregated/index.md) used to aggregate the data. The Aggregation Function can be one of multiple types: - `SUM`: sums the values of the specified column - `PERCENTAGE`: calculates the percentage of the specified column The default denominator for Percentage is the `SUM` of the specified columns, but this can be overridden - `AVG`: calculates the average of the specified column - `MIN`: returns the minimum value of the specified column - `MAX`: returns the maximum value of the specified column - `COUNT`: returns the number of items in the specified column - `MEDIAN`: returns the middle value in the specified column - `MODE`: returns the most popular item in the specified column - `DISTINCT`: returns the number of distinct items in the specified column - `ONLY`: returns the the specified column's value if all are the same - `STD_DEVIATION`: returns the standard deviation for the specified column - Further Aggregation Functions will be added in future releases in response to user requests - Developers can provide their own Custom Aggregation Functions to supplement this list ### `COLUMN` This is the [Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) that contains the values being aggregated. ### Examples At its most basic just an [Aggregation Function](#aggregation_function) and a [Column](#column) is required: ```ts [[1, 2, "SUM"], [2, 2, "PnL"]] // Return sum of all PnL cells SUM([PnL]) ``` ```ts [[1, 2, "MIN"], [2, 2, "Price"]] // Return the lowest Price in the Grid MIN([Price]) ``` The Column that is being aggregated can itself be a Calculated Column (i.e. one which itself is evaluated using an Aggregated Expression) ```ts [[1, 5, "SUM"], [2, 5, "totalPrice"]] // Create a Calculated Column which displays the Price plus VAT CalculatedColumns: [{ ColumnId: 'totalPrice', Query: { ScalarExpression: '[price] + [VAT]'}] // Expression returns sum of all totalPrice Columns i.e. all Prices in the Grid with VAT SUM([totalPrice]) ``` The `AVG` Aggregation Function can receive an optional `WEIGHT` parameter to create [Weighted Averages](https://www.adaptabletools.com/docs/handbook-aggregation-weighted-average/index.md): ```ts [[1, 2, "AVG"], [2, 2, "Price"], [3, 2, "WEIGHT"]] // Return the Weighted Average for the Price Column (using Index column for weighting) AVG([Price], WEIGHT([index])) ``` **Example: AdapTableQL: Scalar Aggregation** Using Scalar Aggregation Expressions in AdapTable - This Demo contains 2 [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) that use Aggregated Scalar Expressions - `Popularity Ratio` - displays a Percentage of `Popularity` Column - `Popularity` is itself a Calculated Column that sums `GitHub Stars` and `GitHub Watchers` - `Total Stars` - shows a Sum of of the GitHub Stars column - because `GROUP_BY` is not added, is the same value in each row - Add a `GROUP_BY` to the Total Stars Expression to Sum according to Language ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Aggregated Scalar Expressions', initialState: { Dashboard: { ModuleButtons: ['CalculatedColumn', 'SettingsPanel'], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'language', 'github_watchers', 'github_stars', 'githubPopularity', 'popularityRatio', 'totalStars', ], AutoSizeColumns: true, }, ], }, CalculatedColumn: { CalculatedColumns: [ { FriendlyName: 'Popularity', ColumnId: 'githubPopularity', Query: { ScalarExpression: '[github_watchers] + [github_stars]', }, CalculatedColumnSettings: { DataType: 'number', }, }, { ColumnId: 'popularityRatio', FriendlyName: 'Popularity Ratio', Query: { AggregatedScalarExpression: 'PERCENTAGE([githubPopularity])', }, CalculatedColumnSettings: { DataType: 'number', }, }, { ColumnId: 'totalStars', FriendlyName: 'Total Stars', Query: { AggregatedScalarExpression: 'Sum([github_stars])', }, CalculatedColumnSettings: { DataType: 'number', }, }, ], }, }, }; ``` ## Boolean Aggregation Expressions Boolean Aggregation Expressions (of type [`Aggregated Boolean Query`](https://www.adaptabletools.com/docs/reference/adaptableaggregatedbooleanquery.md)) are similar to Scalar Aggregation Expressions but only return a true / false value. - This is ideal for Limits Management and related scenarios - For instance where you want to check that a sum comprising multiple cell values has not been exceeded In addition to [Aggregation Function](#aggregation_function) and [Column](#column), 2 addtional elements are typically required: ### `` This defines the operator which is used to compare the aggregated value with the threshold. At present the following comparison operators are supported: - `=` - Equals - `!=` - Not Equals - `>` - Greater Than - `<` - Less Than - `>=` - Greater Than or Equals - `<=` - Less Than or Equals ### `` The Threshold is the (numeric) value that is being compared against the aggregated value. aa In place of absolute numbers, `` can comprise a number with a string abbreviation. The following shortcuts can be used: - `K`: thousand (e.g. '5K') - `M`: million (e.g. '2M') - `B`: billion (e.g. '4B') When using a threshold shortcut the value must be placed in quotation marks ### Examples ```ts [[1, 2, "SUM"],[2, 2, "PnL"],[3, 2, ">"],[4, 2, "5000000"]] // Is total value of the 'PnL' column in all rows > 5 Million SUM([PnL]) > '5000000' ``` ```ts [[1, 2, "SUM"],[2, 2, "PnL"],[3, 2, ">"],[4, 2, "5M"]] // Alternate form of above Expression but using abbreviated threshold notation SUM([PnL]) > '5M' ``` ```ts [[1, 2, "MIN"],[2, 2, "Bid"],[3, 2, "="],[4, 2, "40K"]] // Is the lowest Bid worth 40,000 MIN([Bid]) = '40K' ``` ```ts [[1, 2, "AVG"],[2, 2, "Price"],[3, 2, ">"],[4, 2, "3M"]] // Is the average Price over 3 Million AVG([Price]) > '3M' ``` **Example: AdapTableQL: Boolean Aggregation** Creating Aggregated Boolean Expressions in AdapTableQL - This demo contains 3 [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) that fire when an Aggregated Boolean Expression is triggered - if the lowest `Github Watchers` values is under 50 - when the total of all the `Github Stars` rows is over 10,000 - when the total of all `Open Issues` rows is over 6,000 - 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 ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Aggregated Boolean Expression', initialState: { Dashboard: { ModuleButtons: ['Alert'], Tabs: [ { Name: 'Toolbars', Toolbars: ['Alert', 'CellSummary'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Alert'], }, ], }, Theme: {CurrentTheme: 'dark'}, Alert: { AlertDefinitions: [ { Name: 'alert-Info-44', MessageType: 'Info', Scope: { All: true, }, Rule: { AggregatedBooleanExpression: 'MIN([github_watchers] ) < 50 ', }, AlertProperties: { DisplayNotification: true, }, }, { Name: 'alert-Success-45', MessageType: 'Success', Scope: { All: true, }, Rule: { AggregatedBooleanExpression: "SUM([github_stars] ) > '10k' ", }, AlertProperties: { DisplayNotification: true, }, }, { Name: 'alert-Warning-46', MessageType: 'Warning', Scope: { All: true, }, Rule: { AggregatedBooleanExpression: "SUM([open_issues_count] ) >'6k'", }, 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, }, ], }, }, }; ``` ## Grouped Aggregation An Aggregation Scalar Function can be applied just to a **group** 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). The `GROUP_BY` function is **always** only used together with an Aggregation Function The `GROUP_BY` function typically receives a single parameter - the name of a [Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md): ```ts [[1, 2, "SUM([PnL]"], [2, 2, "GROUP_BY([Currency])"]] // Return Sum of all Pnl cells for rows which have this row's Currency value SUM([PnL], GROUP_BY([Currency]) ) ``` It is particularly useful when used with the `COUNT` function to give the numbers in each group: ```ts [[1, 2, "COUNT([Currency]"], [2, 2, "GROUP_BY([Currency])"]] // Return count of all rows in the Grid which have the same Currency as this one COUNT([Currency], GROUP_BY([Currency]) ) ``` For more advanced use cases, the `GROUP_BY` function can receive multiple Columns: ```ts [[1, 2, "SUM([PnL]"], [2, 2, "GROUP_BY([Currency], [Counterparty])"]] // Return Sum of all Pnl cells for rows which have this row's Currency and Counterparty values SUM([PnL], GROUP_BY([Currency], [Counterparty]) ) ``` ### How Grouped Aggregation Works The name `GROUP_BY` comes from a command in the SQL DB language. However it is perhaps more illuminative to think of it as a succession of: 1. __split__: the rows are split into groups based on the value of the specified column 2. __apply__: the aggregation function is applied within each individual group 3. __combine__: the aggregation results are combined back into each row **Example: AdapTableQL: Grouped Aggregation** Using Scalar Aggregation Expressions with Grouping - This Demo contains 4 [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) that use Aggregated Scalar Expressions with Grouping - `Watchers By Lang` - Sum of of the GitHub Watchers column, grouped by Language - `Avg. Lang Popularity` - Average of Github Stars popularity, grouped by language - `Open/Closed Issues % by Lang` - Percentage of Open and Closed issues, grouped by language - `Lang Count` - Count of each language, also grouped language ### Expand to see the Aggregated and Grouped Scalar Expressions The 3 Calculated Columns are defined as follows: ``` CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'total-watchers-by-lang', FriendlyName: 'Watchers By Lang', Query: { AggregatedScalarExpression: 'Sum([github_watchers])', }, CalculatedColumnSettings: { DataType: 'number', }, }, { ColumnId: 'average-popularity-by-lang', FriendlyName: 'Avg. Popularity by Lang', Query: { AggregatedScalarExpression: 'AVG([github_stars], 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', }, }, { ColumnId: 'lang-count', FriendlyName: 'Lang Count', Query: { AggregatedScalarExpression: 'COUNT([language], GROUP_BY([language])) ', }, CalculatedColumnSettings: { DataType: 'number', }, }, ]} ``` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Aggregated Scalar GroupBy Expressions', initialState: { Dashboard: { ModuleButtons: ['CalculatedColumn', 'SettingsPanel'], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'language', 'lang-count', 'github_watchers', 'github_stars', 'total-watchers-by-lang', 'average-popularity-by-lang', 'percentage-issues-by-lang', ], AutoSizeColumns: true, }, ], }, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'total-watchers-by-lang', FriendlyName: 'Watchers By Lang', Query: { AggregatedScalarExpression: 'Sum([github_watchers], GROUP_BY([language]))', }, CalculatedColumnSettings: { DataType: 'number', }, }, { ColumnId: 'average-popularity-by-lang', FriendlyName: 'Avg. Lang Popularity', Query: { AggregatedScalarExpression: 'AVG([github_stars], 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', }, }, { ColumnId: 'lang-count', FriendlyName: 'Lang Count', Query: { AggregatedScalarExpression: 'COUNT([language], GROUP_BY([language])) ', }, CalculatedColumnSettings: { DataType: 'number', }, }, ], }, }, }; ``` ## `WHERE` Clause Optionally, a `WHERE` clause may be appended to an Aggregated Boolean Expression. This is used to narrow down the scope of the 'main' part of the Expression. The `WHERE` Clause takes the form of a [Standard Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md). ```ts [[1, 2, "SUM"],[2, 2, "PnL"],[3, 2, ">"],[4, 2, "5M"],[5, 2, "WHERE [Currency] = 'USD'"]] // Are all PnL values in rows with Dollar Currency over 5M SUM([PnL]) > '5M' WHERE [Currency] = 'USD' ``` ```ts [[1, 2, "SUM"],[2, 2, "PnL"],[3, 2, ">"],[4, 2, "5M"],[5, 2, "WHERE [Currency] = 'USD' AND [RequiredDate] < ADD_DAYS(CURRENT_DAY, 30)"]] // Similar Expression to above but with more complex WHERE Clause SUM([PnL]) > '5M' WHERE [Currency] = 'USD' AND [RequiredDate] < ADD_DAYS(CURRENT_DAY, 30) ``` **Example: AdapTableQL: Boolean Aggregations with WHERE** Aggregated Boolean Expressions with WHERE Clauses - This demo contains 2 [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) that fire when an Aggregated Boolean Expression is triggered. - Both are the same Aggregation Boolean Expressions as in the demo above but with a `WHERE` clause added: - when the total of `Github Stars` is over 10,000 - **only** for rows where `Licence` is 'MIT License' - when the total of `Open Issues` is over 6,000 - **only** for rows where `Language` is 'JavaScript' - In the first row change the value of: - `Github Stars` column to 279429 and see the `Success` Alert be fired (because `Licence` in first row is "MIT License") - `Open Issues` column to 1220 and see the `Warning` Alert be fired (because `Language` in first row is "JavaScript") ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Aggregated Boolean Expression', initialState: { Dashboard: { ModuleButtons: ['Alert'], Tabs: [ { Name: 'Toolbars', Toolbars: ['Alert', 'CellSummary'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Alert'], }, ], }, Theme: {CurrentTheme: 'dark'}, Alert: { AlertDefinitions: [ { Name: 'alert-Success-47', MessageType: 'Success', Scope: { All: true, }, Rule: { AggregatedBooleanExpression: "SUM([github_stars] ) > '10k' WHERE [license] = 'MIT License'", }, AlertProperties: { DisplayNotification: true, }, }, { Name: 'alert-Warning-48', MessageType: 'Warning', Scope: { All: true, }, Rule: { AggregatedBooleanExpression: "SUM([open_issues_count] ) >'6k' WHERE [language] = 'JavaScript' ", }, 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, }, ], }, }, }; ``` --- # Aggregation Boolean Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation-boolean This AdapTable Help Page no longer exists. Instead please read the guide to [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) --- # Aggregation Scalar Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation-scalar This AdapTable Help Page no longer exists. Instead please read the guide to [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) --- # Configuring Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-configuring - Expressions in AdapTable can be configured to meet precise needs including: - Providing Column Friendly Names - Using Case Sensitivity - Performing Validation --- # Cumulative (Aggregation) Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-cumulative - AdapTableQL performs cumulative aggregations by using the `CUMUL` and `OVER` functions Cumulative Expressions, as the name suggests, perform **cumulative** Aggregations. This is particularly useful when calculating Running Totals In this use case, the *Aggregation Operation* is applied to each row in the set cumulatively. Cumulative Expressions are actually a special case of [Aggregation Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) ## Aggregation Operations There are 5 Aggregation Operations available when using Cumulative Aggregations: - `SUM` - `MIN` - `MAX` - `AVG` - `PERCENTAGE` ## Using `OVER` to set Order The Aggregation Operation in a Cumulative Aggregation is applied in a **specific order**. That order is specified in the Expression by the `OVER` keyword operator. This takes the name of an [Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) as its sole parameter. The `OVER` operator only works with Columns of type `date` or `number` ```ts [[1, 2, "CUMUL"], [2, 2, "SUM([PnL])"], [3, 2, "OVER([TradeDate])"]] // Derive cumulative sum of all PnL columns according to TradeDate order CUMUL(SUM([PnL]), OVER([TradeDate])) ``` ```ts [[1, 2, "CUMUL"], [2, 2, "MAX([PnL])"], [3, 2, "OVER([TradeDate])"]] // Calculate cumulative maximum value of all PnL columns according to TradeDate order CUMUL(MAX([PnL]), OVER([TradeDate])) ``` - There is no need physically to sort the Grid using the column specified by `OVER` - Indeed, the beauty of `OVER` is that *ignores* the current Grid Sort and uses the order in the given Column **Example: AdapTableQL: Cumulative Aggregation** Using Cumulative Scalar Aggregation Expressions - This demo contains 2 [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) that use Cumulative Aggregation Scalar Expressions: - `Cumul Stars` - displays the cumulative sum of stars count of all repos in the grid, aggregated over the `Created` date - `Max Technical Debt` - shows the cumulative maxima of open issues of all repos in the grid, aggregated over the `GitHub Stars` count ### Expand to see the Aggregated Cumulative Scalar Expressions The 2 Calculated Columns are defined as follows: ``` CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'cumul-stars-count', FriendlyName: 'Cumul Stars', Query: { AggregatedScalarExpression: 'CUMUL( SUM([github_stars]), OVER([created_at]) )', }, CalculatedColumnSettings: { DataType: 'number' }, }, { ColumnId: 'max-tech-debt-over-stars', FriendlyName: 'Maxi 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: 'Aggregated Scalar Cumulative Expressions', initialState: { Dashboard: { ModuleButtons: ['CalculatedColumn', 'SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['CellSummary'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'created_at', 'language', 'github_stars', 'open_issues_count', 'cumul-stars-count', 'max-tech-debt-over-stars', ], ColumnSorts: [{ColumnId: 'created_at', SortOrder: 'Asc'}], AutoSizeColumns: true, }, ], }, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'cumul-stars-count', FriendlyName: 'Cumul Stars', Query: { AggregatedScalarExpression: 'CUMUL( SUM([github_stars]), OVER([created_at]) )', }, CalculatedColumnSettings: { DataType: 'number', Resizable: true, Width: 200, }, }, { ColumnId: 'max-tech-debt-over-stars', FriendlyName: 'Max Technical Debt', Query: { AggregatedScalarExpression: 'CUMUL( MAX([open_issues_count]), OVER([github_stars]) )', }, CalculatedColumnSettings: { DataType: 'number', Resizable: true, Width: 200, }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-created_at', Scope: { ColumnIds: ['created_at'], }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'yyyy/MM/dd', }, }, }, { Name: 'formatColumn-number', Scope: { DataTypes: ['number'], }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { IntegerSeparator: ',', }, }, }, ], }, }, }; ``` ## Grouped Cumulative Aggregation Like with Standard Scalar Aggregations, Cumulative Aggregations can be grouped. Aging this is accomplished by using the `GROUP_BY` function. `GROUP_BY` is applied as a parameter to the Aggregation operator being used (e.g. `SUM`) and not to `CUMUL` ```ts [[1, 2, "CUMUL"], [2, 2, "SUM([PnL],"], [3, 2, "GROUP_BY([currency])"], [4, 2, "OVER([TradeDate])"]] // Cumulative sum of all PnL columns ordering by TradeDate, grouping by Currency CUMUL(SUM([PnL], GROUP_BY([currency])), OVER([TradeDate])) ``` Similar to Standard Scalar Aggregations, there is no limit on the number of Columns which can be grouped. ```ts [[1, 2, "CUMUL"], [2, 2, "SUM([PnL],"], [3, 2, "GROUP_BY([currency], [country])"], [4, 2, "OVER([TradeDate])"]] // Cumulative sum of all PnL columns ordering by TradeDate, grouping by Currency and Country CUMUL(SUM([PnL], GROUP_BY([currency], [country])), OVER([TradeDate])) ``` **Example: AdapTableQL: Cumulative Aggregations Grouped** Using Cumulative Scalar Aggregations with Grouping - This demo contains 2 [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) that use Cumulative Aggregation Scalar Expressions, one with grouping: - `Cumul Stars` - displays the cumulative sum of stars count of **all repos** in the grid, aggregated over the `Created` date (same as in demo above) - `Cumul Lang Stars` - displays the cumulative sum of stars count in the grid, but grouped by `Language`, and aggregated over the `Created` date ### Expand to see the Aggregated Cumulative Scalar Expressions The 2 Calculated Columns are defined as follows: ``` CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'cumul-stars-count', FriendlyName: 'Cumul Stars', Query: { AggregatedScalarExpression: 'CUMUL( SUM([github_stars]), OVER([created_at]) )', }, CalculatedColumnSettings: { DataType: 'number' }, }, { ColumnId: 'cumul-language-stars-count', FriendlyName: 'Cumul Lang Stars', Query: { AggregatedScalarExpression: 'CUMUL( SUM([github_stars], GROUP_BY([language])), OVER([created_at]) )', }, CalculatedColumnSettings: { DataType: 'number' }, }, ] } ``` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Aggregated Scalar Cumulative Expressions Grouped', initialState: { Dashboard: { ModuleButtons: ['CalculatedColumn', 'SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['CellSummary'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'created_at', 'language', 'github_stars', 'open_issues_count', 'cumul-stars-count', 'cumul-language-stars-count', 'max-tech-debt-over-stars', ], ColumnSorts: [ {ColumnId: 'language', SortOrder: 'Asc'}, {ColumnId: 'created_at', SortOrder: 'Asc'}, ], AutoSizeColumns: true, }, ], }, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'cumul-stars-count', FriendlyName: 'Cumul Stars', Query: { AggregatedScalarExpression: 'CUMUL( SUM([github_stars]), OVER([created_at]) )', }, CalculatedColumnSettings: { DataType: 'number', Resizable: true, Width: 200, }, }, { ColumnId: 'cumul-language-stars-count', FriendlyName: 'Cumul Lang Stars', Query: { AggregatedScalarExpression: 'CUMUL( SUM([github_stars], GROUP_BY([language])), OVER([created_at]) )', }, CalculatedColumnSettings: { DataType: 'number', Resizable: true, Width: 200, }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-created_at', Scope: { ColumnIds: ['created_at'], }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'yyyy/MM/dd', }, }, }, { Name: 'formatColumn-number', Scope: { DataTypes: ['number'], }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { IntegerSeparator: ',', }, }, }, ], }, }, }; ``` --- # AdapTableQL Expression Functions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-functions - This section lists all the Expression Functions shipped with [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) - They have been categorised according to the Expression Function's return type Expression Functions are a key part of any Expression. AdapTable ships with a huge range of Expression Functions (while developers can provide their own). For convenience, we have sorted these functions into 5 conceptual groups: | Type | Returns | Available in Expressions | | ------------------------------------------------------------------------------------- | --------------------------------- | --------------------------------- | | [Standard](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-standard/index.md) | Single value of any return type | Standard, Observable, Aggregation | | [Aggregated](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-aggregated/index.md) | Single value of any return type | Aggregation | | [Relative Change](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-relative-change/index.md) | Single value of any return type | Standard | | [Observable](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-observable/index.md) | The results of Changes it watches | Observable | | [Custom](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom/index.md) | Boolean or Scalar | Per Custom Function definition | - You can use **Standard** Functions in **ALL** types of Expressions - For instance its likely that an Aggregation Expression will include at least one Standard function --- # Advanced Expression Functions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-advanced - This section lists the Expression Functions used in Advanced Expression use cases There are some "specialised" Expression Functions available when writing [Advanced Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced/index.md): | Function | When Used | Example | | ------------------------------ | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | | QUERY | Referencing [Named Queries](https://www.adaptabletools.com/docs/handbook-named-queries/index.md) | ```QUERY('my named query')``` | | VAR | Referencing [Custom Variables](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-var-function/index.md) | ```VAR("VAT",[country])``` | | FIELD | Referencing (non-column) [Fields](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-row-data/index.md) | ``` FIELD('stars_multiplier')``` | | IF (or ?) | When using [Ternary Logic](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-logic/index.md#if-function) | ```[Comments] > 100 ? 'Big' : 'Small'``` | | CASE
THEN
WHEN
END | When using [CASE Statements](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-logic/index.md#case-statements) | ```CASE [day] WHEN 'Sunday' THEN 'off' ELSE 'work' END``` | --- # Aggregated Expression Functions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-aggregated - This page lists all the Aggregated Expression Functions shipped by AdapTable - These functions iterate over multiple valuues and return a single value (of any type) AdapTableQL provides a large range of Aggregated Expression Functions. These are available in [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md). ## Standard Aggregations AdapTable provides a large set of Aggregated Functions that can be used in Aggregated Expressions. These Aggregation Functions are also used when displaying [Cell Summaries](https://www.adaptabletools.com/docs/handbook-summarising-cells/index.md) and [Row Summaries](https://www.adaptabletools.com/docs/handbook-summarising-rows/index.md) All these functions are **Aggregation Scalar**: recieving a Column (or array) as an input and returning a single value | Function | Example | Returns | Columns | | ------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------- | ------------- | | SUM | ```SUM([col1])``` | Sum of the Column Values | Numeric | | PERCENTAGE | ```PERCENTAGE([col1])``` | Percentage of Column Values | Numeric | | AVG | ```AVG([col1])``` | Average of Column Values | Numeric | | MIN | ```MIN([col1])``` | Minimum value in Column | Numeric, Date | | MAX | ```MAX([col1])``` | Maximum value in Column | Numeric, Date | | MEDIAN | ```MEDIAN([col1])``` | Middle value in Column | Numeric | | COUNT | ```COUNT([col1])``` | Number of values in Column | All | | MODE | ```MODE([col1])``` | Most popular value in Column | All | | DISTINCT | ```DISTINCT([col1])``` | No. of distinct values in Column | All | | ONLY | ```ONLY([col1])``` | Value in Column if all distinct | All | | STD_DEVIATION | ```STD_DEVIATION([col1])``` | Standard Deviation for Column | Numeric | | WEIGHT | ```AVG([c1], WEIGHT([c2]))``` | Used with `AVG` in [Weighted Averages](https://www.adaptabletools.com/docs/handbook-aggregation-weighted-average/index.md) | Numeric | ## GROUP_BY & WHERE 2 additional Expression Functions keywords are often used in conjunction with [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md): | Function | Example | Description | | -------- | -------------------------------------- | ----------------------------------------------------------------------------------------- | | GROUP_BY | ```SUM([col1],GROUP_BY([col2]))``` | Groups aggregation operation within rows that have the same value in the specified column | | WHERE | ```SUM([col1])>5 WHERE [col2]='USD'``` | Narrows scope of Aggregated Expression | ## Cumulative Aggregations 2 Expression Functions keywords are required when creating [Cumulative Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-cumulative/index.md): | Function | Example | Description | | -------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------- | | CUMUL | ```CUMUL(SUM([col1]))``` | Performs cumulative aggregation (running total) with given aggregation operation over a provided column | | OVER | ```CUMUL(SUM([col1]),OVER([col2]))``` | Defines accumulative dimension (order) for enclosing cumulative aggregation | ## Quantile Aggregations 3 Expression Functions keywords are available when creating [Quantile Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-quantile/index.md): Each of these Quantile Aggregations can also be provided with a `GROUP_BY` function | Function | Example | Description | | ---------- | ------------------------ | ------------------------------------------------------------- | | QUANT | ```QUANT([col1], 4)``` | Enables aggregations to be placed into 'n' Quantile 'buckets' | | QUARTILE | ```QUARTILE([col1])``` | Enables aggregations to be placed into 4 Quantile 'buckets' | | PERCENTILE | ```PERCENTILE([col1])``` | Enables aggregations to be placed into 100 Quantile 'buckets' | --- # Custom Expression Functions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom - Custom Expression Functions are AdapTableQL [Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) provided at design-time - They are registered with the AdapTableQL evaluation engine and available for use in AdapTable - They can be Standard (single-row) or Aggregated (multiple-rows) - They are also listed in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) with full help - Custom Expression Functions may be provided only to specific Adaptable Modules AdapTableQL ships with a huge range of [Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md). These allow run-time users to create powerful, and sometimes very complex queries. Additionally, AdapTableQL can be extended through bespoke, custom, expression functions. - Custom Expression Functions extend the [AdapTableQL Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) available in AdapTable - Use [Custom Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) to extend [Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) (used in Column Filters and elsewhere) Custom Expression functions return a single value, either a boolean (ie. true / false) or other value. They can be divided into 2 types: - [Standard](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom-standard/index.md) - evaluate on a single row in the Grid - [Aggregation](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom-aggregation/index.md) - evaluate against a set of rows in the Grid By default every Custom Expression Function created is available in all [Modules](https://www.adaptabletools.com/docs/technical-reference-adaptable-modules/index.md) in AdapTable. However this can be changed by setting the [Custom Expression Function Scope](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom-scope/index.md) which limits where the Expression function is available. --- # Aggregated Custom Expression Functions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom-aggregation - Aggregated Custom Expression Functions work on an array of data and return a single value - This allows users to create Functions that operate on multiple rows or an entire column Developers are able to provide Custom **Aggregation** Expression Functions to AdapTableQL. These are functions which operate against an array of data and return a single value. The array of data provided to the Expression is often a column name, but this does not have to be the case Custom Expression Functions are defined in the `customAggregatedFunctions` property in [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md). ### `customAggregatedFunctions` Custom Aggregated Expression Functions available in AdapTableQL This property provides Custom Aggregated Expression Functions to be added to AdapTableQL; it has the signature: ```ts customAggregatedFunctions?: | Record | ((context: GlobalExpressionFunctionsContext) => Record); ``` The property returns a record of type string and AggregatedExpressionFunction either directly or via a function. ### Anatomy of an Custom Aggregated Expression Function A Custom Aggregated Function is of type [`AggregatedExpressionFunction`](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md) which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [description](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md#description) | `string` | Description of the Aggregated Expression Function | | [examples](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md#examples) | `string[]` | Examples to use the Aggregated Expression Function | | [filterRow](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md#filterrow) | `(context: `[`AggregatedExpressionFilterRowContext`](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfilterrowcontext.md)`) => boolean` | Optional filter which is applied to each row before the reducer is called. If the filter returns false, the row is NOT included in the aggregation. | | [initialValue](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md#initialvalue) | `any` | Mandatory Initial Value for the aggregation | | [inputTypes](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md#inputtypes) | [`ExpressionFunctionInputType`](https://www.adaptabletools.com/docs/reference/expressionfunctioninputtype.md)`[]` | Optional argument types. | | [isAvailable](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md#isavailable) | [`AdaptableModule`](https://www.adaptabletools.com/docs/reference/adaptablemodule.md)`[] \| ((context: `[`ExpressionFunctionAvailabilityContext`](https://www.adaptabletools.com/docs/reference/expressionfunctionavailabilitycontext)`) => boolean)` | Where the function is available — same semantics as `ExpressionFunction.isAvailable`: `undefined` means all modules, an array restricts to the listed modules, a callback decides dynamically. | | [prepareRowValue](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md#preparerowvalue) | `(context: `[`AggregatedExpressionPrepareRowValueContext`](https://www.adaptabletools.com/docs/reference/aggregatedexpressionpreparerowvaluecontext.md)`) => number \| string \| Date \| undefined` | Called for each row AFTER the reducer() and processAggregatedValue() functions Can be used when each row has a different aggregated value (e.g. percentage = row value / aggregated value). Returns return value for each individual row | | [processAggregatedValue](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md#processaggregatedvalue) | `(context: `[`AggregatedExpressionProcessAggValueContext`](https://www.adaptabletools.com/docs/reference/aggregatedexpressionprocessaggvaluecontext.md)`) => any` | Called AFTER the reducer() has processed all values / rows Can be used to change result of reducer based on the values array (e.g. average = aggregated value / count) | | [reducer](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md#reducer) | `(context: `[`AggregatedExpressionReducerContext`](https://www.adaptabletools.com/docs/reference/aggregatedexpressionreducercontext.md)`) => any` | Mandatory Reducer function which is called for each value(row) in the Column Data | | [signatures](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md#signatures) | `string[]` | Example Signatures for the Aggregated Expression Function | As can be seen there are a number of properties which can provided in the Expression Function definition. Here we will list some of the most important. - 2 props - `initialValue` and `reducer` - are mandatory; the others are available for advanced use cases - Many of these properties are functions which receive a unique rich, context object to assist in the evaluation

initialValue (mandatory)

The `initialValue` property provides the **start value** for the aggregation.

reducer (mandatory)

This is the main function which performs the **evaluation** on each element in the data, can return **any** value. It receives `context` of type [`AggregatedExpressionReducerContext`](https://www.adaptabletools.com/docs/reference/aggregatedexpressionreducercontext.md), which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [accumulator](https://www.adaptabletools.com/docs/reference/aggregatedexpressionreducercontext.md#accumulator) | `any` | Value returned by the previous call to the reducer function, or the initialValue if this is the first call. You return the new accumulator value from this function. | | [aggColumnId](https://www.adaptabletools.com/docs/reference/aggregatedexpressionreducercontext.md#aggcolumnid) | `string` | Column Id of the column being aggregated | | [args](https://www.adaptabletools.com/docs/reference/aggregatedexpressionreducercontext.md#args) | `any[]` | Arguments passed to the function | | [currentValue](https://www.adaptabletools.com/docs/reference/aggregatedexpressionreducercontext.md#currentvalue) | `any` | Current value being processed in the Column Data | | [getValueForColId](https://www.adaptabletools.com/docs/reference/aggregatedexpressionreducercontext.md#getvalueforcolid) | `(colId: string) => any` | Helper function to get the value of a column | | [groupByColumnIds](https://www.adaptabletools.com/docs/reference/aggregatedexpressionreducercontext.md#groupbycolumnids) | `string[]` | Column Id(s) of the column(s) being grouped by | | [index](https://www.adaptabletools.com/docs/reference/aggregatedexpressionreducercontext.md#index) | `number` | Index of the current value in the Column Data | | [rowNode](https://www.adaptabletools.com/docs/reference/aggregatedexpressionreducercontext.md#rownode) | `IRowNode` | Current row node | | [adaptableContext](https://www.adaptabletools.com/docs/reference/aggregatedexpressionreducercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | For more complicated scenarios, 4 additional, optional, functions can be provided:

processAggregatedValue

This function is used to change the result of the Aggregated value. It is called **after** the `reducer` has processed all values / rows. It receives `context` of type [`AggregatedExpressionProcessAggValueContext`](https://www.adaptabletools.com/docs/reference/aggregatedexpressionprocessaggvaluecontext.md), which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [aggColumnId](https://www.adaptabletools.com/docs/reference/aggregatedexpressionprocessaggvaluecontext.md#aggcolumnid) | `string` | Column Id of the column being aggregated | | [aggregatedValue](https://www.adaptabletools.com/docs/reference/aggregatedexpressionprocessaggvaluecontext.md#aggregatedvalue) | `any` | Result of the reducer | | [args](https://www.adaptabletools.com/docs/reference/aggregatedexpressionprocessaggvaluecontext.md#args) | `any[]` | Arguments passed to the function | | [groupByColumnIds](https://www.adaptabletools.com/docs/reference/aggregatedexpressionprocessaggvaluecontext.md#groupbycolumnids) | `string[]` | Column Id(s) of the column(s) being grouped by | | [rowNodes](https://www.adaptabletools.com/docs/reference/aggregatedexpressionprocessaggvaluecontext.md#rownodes) | `IRowNode[]` | Array of row nodes; if aggregation is grouped, this will be the array of row nodes for the group | | [adaptableContext](https://www.adaptabletools.com/docs/reference/aggregatedexpressionprocessaggvaluecontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |

prepareRowValue

This function can be used when each row has a different aggregated value (e.g. percentage = row value / agg value). It is called for each row **after** the `reducer` and `processAggregatedValue` functions. It returns the return value for each individual row. It receives `context` of type [`AggregatedExpressionPrepareRowValueContext`](https://www.adaptabletools.com/docs/reference/aggregatedexpressionpreparerowvaluecontext.md), which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [aggColumnId](https://www.adaptabletools.com/docs/reference/aggregatedexpressionpreparerowvaluecontext.md#aggcolumnid) | `string` | Column Id of the column being aggregated | | [aggregatedValue](https://www.adaptabletools.com/docs/reference/aggregatedexpressionpreparerowvaluecontext.md#aggregatedvalue) | `any` | Result of the reducer | | [args](https://www.adaptabletools.com/docs/reference/aggregatedexpressionpreparerowvaluecontext.md#args) | `any[]` | Arguments passed to the function | | [getValueForColId](https://www.adaptabletools.com/docs/reference/aggregatedexpressionpreparerowvaluecontext.md#getvalueforcolid) | `(colId: string) => any` | Helper function to get the value of a column | | [groupByColumnIds](https://www.adaptabletools.com/docs/reference/aggregatedexpressionpreparerowvaluecontext.md#groupbycolumnids) | `string[]` | Column Id(s) of the column(s) being grouped by | | [rowNode](https://www.adaptabletools.com/docs/reference/aggregatedexpressionpreparerowvaluecontext.md#rownode) | `IRowNode` | Current Row Node | | [adaptableContext](https://www.adaptabletools.com/docs/reference/aggregatedexpressionpreparerowvaluecontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |

filterRow

This function provides a filter which is applied to each row **before** the reducer is called. If the filter returns *false*, the row is **not** included in the aggregation. It receives `context` of type [`AggregatedExpressionFilterRowContext`](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfilterrowcontext.md), which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [aggColumnId](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfilterrowcontext.md#aggcolumnid) | `string` | Column Id of the column being aggregated Usually the first Col argument, e.g. [colId] | | [args](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfilterrowcontext.md#args) | `any[]` | Arguments passed to the function | | [getValueForColId](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfilterrowcontext.md#getvalueforcolid) | `(colId: string) => any` | Utility function to get the value of a column | | [groupByColumnIds](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfilterrowcontext.md#groupbycolumnids) | `string[]` | Column Id(s) of the column(s) being grouped by | | [rowNode](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfilterrowcontext.md#rownode) | `IRowNode` | Current row node | | [adaptableContext](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfilterrowcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |

args

All the Context objects include an `args` property in which column arguments are transformed to their values. For example: [colId] -> args = [value-of-colId] Aggregation Column and "Group By" Columns are **not** included as they are passed as separate arguments

getValueForColId

Another property available in most Context objects is `getValueForColId`. This is a very useful utility function to get the value of a column and has this signature: ``` getValueForColId: (colId: string) => any; ``` ### Defining a Custom Aggregated Expression Function In this Guide we create 5 Custom Aggregated Expression Functions: - `PRODUCT` - a straightforwrd function that returns the product of a series of numbers - `SUMSQ` - a straightforwrd function that Mimics SUMSQL in Excel, returning sum of squares of numbers - `RANK` - returns the rank of a number in a list - leverages more advanced properties available in the Function definition - `LARGE` - returns the Kth biggest number in a list (where K is an input) - also leverages advanced Function definition properties - `TOP` - returns *true* / *false* per row indicating whether the row's value is among the K largest in the list (combines `processAggregatedValue` and `prepareRowValue`) Add the Custom Expression Function definition to the `customAggregatedFunctions` section in Expression Options Each entry is of type Record with the key and value as follows: - key is the custom Function's `name` (by convention, it is in CAPITAL LETTERS - to make it more readable when used in an Expression) - value is the Function's definition (which is of type: [`AggregatedExpressionFunction`](https://www.adaptabletools.com/docs/reference/aggregatedexpressionfunction.md)) Use the `initialValue` property to set the **start** value for the aggregation This function will be called for **each** value (typically a row) in the Column Data The context object provided to the function includes: - `accumulator` - value returned by the previous call to the reducer function, or the initialValue if this is the first call. You return the new accumulator value from this function - `currentValue` - current value being processed in Column Data - `index` - index of current value in the Column Data Called **after** the `reducer` has processed all values / rows Can be used to change result of reducer based on the values array (e.g. average = aggregated value / count) The function context includes: - `aggregatedValue` - result of the reducer - `rowNodes` - array of row nodes (if aggregation was grouped, this will be array of row nodes for the group) Called for each row **after** the `reducer` and `processAggregatedValue` functions. Can be used when each row has a different aggregated value (e.g. percentage = row value / aggregated value) The function context inlucdes the current row node. There are 3 properties that should be provided in order to help Users accessing the Function in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md): - `description`: Explains what the Function does - `signatures`: Shows how the Function should be called - `examples`: Small examples of Function in action ```ts [[1,2, "customAggregatedFunctions"], [1,3, "PRODUCT"], [1,12, "SUMSQ"], [1,22, "RANK"], [1,56, "LARGE"], [1,79, "TOP"],[2,4, "initialValue"],[2,13, "initialValue"],[2,23, "initialValue"],[2,57, "initialValue"],[2,80, "initialValue"],[3,5, "reducer"],[3,14, "reducer"],[3,24, "reducer"],[3,58, "reducer"],[3,81, "reducer"],[4,30, "processAggregatedValue"],[4,65, "processAggregatedValue"],[4,87, "processAggregatedValue"],[5,42, "prepareRowValue"],[5,108, "prepareRowValue"],[6,8, "description"], [6,17, "description"],[6,52, "description"],[6,75, "description"],[6,117, "description"],[6,9, "signatures"],[6,19, "signatures"],[6,53, "signatures"],[6,76, "signatures"],[6,118, "signatures"],[6,10, "examples"],[6,20, "examples"],[6,54, "examples"],[6,77, "examples"],[6,119, "examples"]] expressionOptions: { customAggregatedFunctions: { PRODUCT: { initialValue: 1, reducer: (context: AggregatedExpressionReducerContext) => { return context.accumulator * context.currentValue; }, description: 'Returns product of an array of values', signatures: ['PRODUCT(numericVals: number[])'], examples: ['PRODUCT([price])'], }, SUMSQ: { initialValue: 1, reducer: (context: AggregatedExpressionReducerContext) => { return context.accumulator + context.currentValue * 2; }, description: 'Mimics SUMSQL in Excel - returning sum of squares of arguments', signatures: ['SUMSQ(numericVals: number[])'], examples: ['SUMSQ([price])'], }, RANK: { initialValue: [], reducer: (context: AggregatedExpressionReducerContext) => { if (context.currentValue != undefined) { context.accumulator.push(context.currentValue); } return context.accumulator; }, processAggregatedValue: ( context: AggregatedExpressionProcessAggValueContext ) => { const sortedDataCollection = context.aggregatedValue.sort( (firstValue: any, secondValue: any) => firstValue - secondValue ); const rankMap = new Map(); sortedDataCollection.forEach((value: any, index: any) => { rankMap.set(value, index + 1); }); return rankMap; }, prepareRowValue: ( context: AggregatedExpressionPrepareRowValueContext ) => { const aggregatedColumnId = context.aggColumnId; const rowValue = context.adaptableApi.gridApi.getRawValueFromRowNode( context.rowNode, aggregatedColumnId ); return context.aggregatedValue.get(rowValue) as number; }, description: 'Mimics RANK in Excel; returns rank of a number in given list', signatures: ['RANK([amount])'], examples: ['RANK([amount])'], }, LARGE: { initialValue: [], reducer: (context: AggregatedExpressionReducerContext) => { if (context.currentValue != undefined) { context.accumulator.push(context.currentValue); context.accumulator.sort((a: any, b: any) => b - a); } return context.accumulator; }, processAggregatedValue: ( context: AggregatedExpressionProcessAggValueContext ) => { const k = context.args[0]; if (k == undefined || k <= 0 || k > context.rowNodes.length) { console.log('Invalid K value for LARGE function: ', k); return; } return context.aggregatedValue[k - 1]; }, description: 'Mimics LARGE in Excel; returns Kth largest number in list', signatures: ['LARGE([price], K: number)'], examples: ['LARGE([price], 4)'], }, TOP: { initialValue: [], reducer: (context: AggregatedExpressionReducerContext) => { if (context.currentValue != undefined) { context.accumulator.push(context.currentValue); } return context.accumulator; }, processAggregatedValue: ( context: AggregatedExpressionProcessAggValueContext ) => { const k = context.args[0]; if (k == undefined || k <= 0) { return new Set(); } const sorted = [...context.aggregatedValue].sort( (a: any, b: any) => b - a ); const threshold = sorted[Math.min(k, sorted.length) - 1]; const topSet = new Set(); for (const v of sorted) { if (v >= threshold) { topSet.add(v); } else { break; } } return topSet; }, prepareRowValue: ( context: AggregatedExpressionPrepareRowValueContext ) => { const rowValue = context.adaptableApi.gridApi.getRawValueFromRowNode( context.rowNode, context.aggColumnId ); return (context.aggregatedValue as Set).has(rowValue); }, description: 'Returns true if the row value is among the K largest values in the list', signatures: ['TOP([colId], K: number)'], examples: ['TOP([amount], 5)'], }, } ``` - In the example above, `LARGE`, `RANK` and `TOP` all require the data to be sorted: - `LARGE` re-sorts on every reduction step - However `RANK` and `TOP` leverage `processAggregatedValue` hook to sort data only **once** after the reducer has finished - They build a `Map` (`RANK`) or `Set` (`TOP`) for an O(1) per-row lookup, resulting in major performance boost with big data **Example: AdapTableQL: Custom Aggregation Functions** Using Custom Expression Functions - This example creates the 5 Custom Aggregation Expression Functions in the Developer Steps above, and references them in various [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md): - `PRODUCT`: multiplies set of values - used in `Total Rating` (product of `Rating` Column) & `Ccy Rating` (product of `Rating` grouped by `Currency`) - `SUMSQ`: return sum of squares of values - used in `Sum Sq Rating` (operates on `Rating` Column) - `LARGE`: returns the K-th largest value in a data set - used in `2nd largest amount` (2nd largest value in `Amount` Column) - `RANK`: returns the rank of a number in a list of numbers - used in `Amt Rank` (ranks the `Amount` Column) - `TOP`: returns *true* if the row value is among the K largest in the column - used in `Top 5 Amt` (flags the 5 largest values in the `Amount` Column) - Open the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) for the Calculated Columns to see the Expressions and the Aggregated Expression Functions - Sort the `Amount` column to and note how the `2nd Large Amt`, `Ranking of Amount` and `Top 5 Amt` columns all stay correct ```ts import { AdaptableOptions, //AggregatedExpressionReducerContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; import { AggregatedExpressionPrepareRowValueContext, AggregatedExpressionProcessAggValueContext, AggregatedExpressionReducerContext, } from '@adaptabletools/adaptable/src/parser/src/types'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom Aggregation Expression Functions', expressionOptions: { customAggregatedFunctions: { PRODUCT: { initialValue: 1, reducer: (context: AggregatedExpressionReducerContext) => { return context.accumulator * context.currentValue; }, description: 'Returns product of an array of values', signatures: ['PRODUCT(numericVals: number[])'], examples: ['PRODUCT([price])'], }, SUMSQ: { initialValue: 1, reducer: (context: AggregatedExpressionReducerContext) => { return context.accumulator + context.currentValue * 2; }, description: 'Mimics SUMSQL in Excel - returning sum of squares of arguments', signatures: ['SUMSQ(numericVals: number[])'], examples: ['SUMSQ([price])'], }, LARGE: { initialValue: [], reducer: (context: AggregatedExpressionReducerContext) => { if (context.currentValue != undefined) { context.accumulator.push(context.currentValue); context.accumulator.sort((a: any, b: any) => b - a); } return context.accumulator; }, processAggregatedValue: ( context: AggregatedExpressionProcessAggValueContext ) => { const k = context.args[0]; if (k == undefined || k <= 0 || k > context.rowNodes.length) { console.log('Invalid K value for LARGE function: ', k); return; } // return the value of the aggregated column for the k-th row node (k-1 because of 0-based index) return context.aggregatedValue[k - 1]; }, description: 'Mimics LARGE in Excel - Returns the K-th largest value in a data set', signatures: ['LARGE([price], K: number)'], examples: ['LARGE([price], 4)'], }, RANK: { description: 'Mimics RANK in Excel - Returns the rank of a number in a list of numbers', signatures: ['RANK([amount])'], examples: ['RANK([amount])'], initialValue: [], reducer: (context: AggregatedExpressionReducerContext) => { // sorting an array is an O(n log n) operation, and doing it for every element would result in an O(n^2 log n) operation // a more efficient way is to sort the array after all elements have been added, in the processAggregatedValue() function if (context.currentValue != undefined) { context.accumulator.push(context.currentValue); } return context.accumulator; }, processAggregatedValue: ( context: AggregatedExpressionProcessAggValueContext ) => { // 1. sort the array and populate the rank map const sortedDataCollection = context.aggregatedValue.sort( (firstValue: any, secondValue: any) => firstValue - secondValue ); // 2. map sorted array to a rank map const rankMap = new Map(); sortedDataCollection.forEach((value: any, index: any) => { rankMap.set(value, index + 1); }); // this aggregatedValue will be passed to prepareRowValue() function return rankMap; }, prepareRowValue: ( context: AggregatedExpressionPrepareRowValueContext ) => { // this function will be called for each row after the reducer() and processAggregatedValue() functions // because the aggregated value is a map, we can get the rank of the current row value with a single lookup (O(1) complexity) const aggregatedColumnId = context.aggColumnId; const rowValue = context.adaptableApi.gridApi.getRawValueFromRowNode( context.rowNode, aggregatedColumnId ); return context.aggregatedValue.get(rowValue) as number; }, }, TOP: { description: 'Returns true if the row value is among the K largest values in the list (ties at the boundary are all included)', signatures: ['TOP([colId], K: number)'], examples: ['TOP([amount], 5)'], initialValue: [], reducer: (context: AggregatedExpressionReducerContext) => { // collect every non-empty value; sort once in processAggregatedValue // for O(n log n) instead of O(n^2 log n) per-row sorting if (context.currentValue != undefined) { context.accumulator.push(context.currentValue); } return context.accumulator; }, processAggregatedValue: ( context: AggregatedExpressionProcessAggValueContext ) => { const k = context.args[0]; if (k == undefined || k <= 0) { console.log('Invalid K value for TOP function: ', k); return new Set(); } // sort descending; the threshold is the K-th largest value const sorted = [...context.aggregatedValue].sort( (a: any, b: any) => b - a ); const threshold = sorted[Math.min(k, sorted.length) - 1]; // build a Set of every value at-or-above the threshold so // prepareRowValue can do an O(1) lookup per row. Including // every value tied with the threshold matches the natural // meaning of "in the top K". const topSet = new Set(); for (const v of sorted) { if (v >= threshold) { topSet.add(v); } else { break; } } return topSet; }, prepareRowValue: ( context: AggregatedExpressionPrepareRowValueContext ) => { const rowValue = context.adaptableApi.gridApi.getRawValueFromRowNode( context.rowNode, context.aggColumnId ); // Cast: the parser's `prepareRowValue` return type doesn't yet // include `boolean`, but boolean calculated columns accept it // at runtime (see `top5_amount` / `top3_amount` below). return (context.aggregatedValue as Set).has(rowValue) as any; }, }, }, }, initialState: { Dashboard: { ModuleButtons: ['CalculatedColumn', 'FormatColumn', 'SettingsPanel'], }, Theme: {CurrentTheme: 'dark'}, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'total_rating', Query: { AggregatedScalarExpression: 'PRODUCT([rating])', }, CalculatedColumnSettings: { DataType: 'number', }, FriendlyName: 'Total Rating', }, { ColumnId: 'currency_rating', Query: { AggregatedScalarExpression: 'PRODUCT([rating], GROUP_BY([currency]))', }, CalculatedColumnSettings: { DataType: 'number', }, FriendlyName: 'Ccy Rating', }, { ColumnId: 'sum_square_rating', Query: { AggregatedScalarExpression: 'SUMSQ([rating])', }, CalculatedColumnSettings: { DataType: 'number', }, FriendlyName: 'Sum Sq Rating', }, { ColumnId: '2nd_largest_amount', Query: { AggregatedScalarExpression: 'LARGE([amount], 2)', }, CalculatedColumnSettings: { DataType: 'number', }, FriendlyName: '2nd Large Amt', }, { ColumnId: 'rank_amount', Query: { AggregatedScalarExpression: 'RANK([amount])', }, CalculatedColumnSettings: { DataType: 'number', }, FriendlyName: 'Amt Rank', }, { ColumnId: 'top5_amount', Query: { AggregatedScalarExpression: 'TOP([amount], 5)', }, CalculatedColumnSettings: { DataType: 'boolean', }, FriendlyName: 'Top 5 Amt', }, { // Helper boolean column used by the `Top 3 Amt` Format Column // below. Hidden from the visible layout — its only purpose is // to expose the aggregated `TOP([amount], 3)` result as a // per-row boolean that a (non-aggregated) `BooleanExpression` // rule can reference. ColumnId: 'top3_amount', Query: { AggregatedScalarExpression: 'TOP([amount], 3)', }, CalculatedColumnSettings: { DataType: 'boolean', }, FriendlyName: 'Top 3 Amt', }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-top3-amount', Scope: { ColumnIds: ['amount'], }, // Highlight the `amount` cell whenever its value is in the // top 3 — driven by the `top3_amount` calculated column, // which itself uses the custom `TOP` aggregation function. // Ties at the 3rd-largest value are all included. // // Note: AdapTableQL boolean literals here must be uppercase // (`TRUE` / `FALSE`); lowercase `true` and a bare column // reference are not currently accepted by the parser. Rule: { BooleanExpression: '[top3_amount] = TRUE', }, Style: { ForeColor: 'blue', FontWeight: 'Bold', }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'item', 'amount', 'rank_amount', '2nd_largest_amount', 'top5_amount', 'currency', 'rating', 'total_rating', 'currency_rating', 'sum_square_rating', ], AutoSizeColumns: true, // RowSummaries: [ // { // Position: 'Top', // ColumnsMap: { // rating: 'PRODUCT', // }, // }, // ], // - Note: We have also used `PRODUCT` in a for the `Rating` Column }, ], }, }, }; ``` ```ts import {ColDef} from 'ag-grid-enterprise'; export const columnDefs: ColDef[] = [ { headerName: 'id', field: 'Id', filter: true, editable: false, sortable: true, cellDataType: 'text', }, { headerName: 'Item', field: 'item', filter: true, editable: false, sortable: true, cellDataType: 'text', }, { headerName: 'Amount', field: 'amount', filter: true, editable: true, sortable: true, cellDataType: 'number', }, { headerName: 'Currency', field: 'currency', filter: true, editable: true, sortable: true, cellDataType: 'text', }, { headerName: 'Purchased', field: 'purchased', filter: true, editable: true, sortable: true, cellDataType: 'date', }, { headerName: 'Rating', field: 'rating', filter: true, editable: true, sortable: true, cellDataType: 'number', }, ]; ``` ```ts export const rowData = [ { id: 1, item: 'Washing Machine', amount: 500.35, currency: 'EUR', purchased: new Date(2023, 5, 11), rating: 2, }, { id: 2, item: 'Football', amount: 2.7, currency: 'GBP', purchased: new Date(2022, 7, 19), rating: 4, }, { id: 3, item: 'Fridge', amount: 385.75, currency: 'USD', purchased: new Date(2021, 4, 5), rating: 3, }, { id: 4, item: 'Food', amount: 195, currency: 'CHF', purchased: new Date(2021, 3, 15), rating: 2, }, { id: 5, item: 'Holiday', amount: 1187.5, currency: 'GBP', purchased: new Date(2019, 8, 7), rating: 1, }, { id: 6, item: 'Misc', amount: 56.23, currency: 'EUR', purchased: new Date(2023, 4, 5), rating: 8, }, { id: 7, item: 'Laptop', amount: 2500, currency: 'EUR', purchased: new Date(2022, 8, 3), rating: 7, }, { id: 8, item: 'Sport Tickets', amount: 904, currency: 'EUR', purchased: new Date(2019, 2, 24), rating: 3, }, { id: 9, item: 'Clothes', amount: 480.25, currency: 'USD', purchased: new Date(2023, 5, 29), rating: 6, }, { id: 10, item: 'Concert Ticket', amount: 235.45, currency: 'USD', purchased: new Date(2023, 7, 15), rating: 4, }, { id: 11, item: 'Rent', amount: 652.75, currency: 'GBP', purchased: new Date(2021, 4, 23), rating: 4, }, ]; ``` --- # Custom Expression Function Scope Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom-scope - Custom Expression Functions may be provided only to specific Adaptable Modules By default every Custom Expression Function created is available in all [Modules](https://www.adaptabletools.com/docs/technical-reference-adaptable-modules/index.md) in AdapTable. However sometimes developers might wish to limit this, and allow the Custom Expression Function to be used in some Modules but not others. This is possible by using the `moduleExpressionFunctions` section in [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md). ### Creating Custom Expression Functions for specific Adaptable Modules In this Guide we will create the same 2 Custom Expression Functions as in the Step by Step Guides above but limit where they can be applied: - the Custom **Boolean** Expression Function will be available only in the `Alert` Module - the Custom **Scalar** Expression Function will be available only in the `CalculatedColumn` Module The `moduleExpressionFunctions` section is a Record with the Adaptable Modules as property keys and the property values of type ([`ModuleExpressionFunctionsMap`](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctionsmap.md)) Module specific functions override globally defined ones. In this case, `Alert.customBooleanFunctions` override the global functions defined in `customBooleanFunctions`. The definition is exactly the same as for the global custom defined functions, each module may define its own: - `systemBooleanFunctions` - `customBooleanFunctions` - `systemScalarFunctions` - `customScalarFunctions` - `systemObservableFunctions` - `systemAggregatedBooleanFunctions` - `systemAggregatedScalarFunctions` Each Module specific functions override the global defined functions. In this case, `CalculatedColumn.customScalarFunctions` override the global functions defined in `ExpressionOptions.customScalarFunctions`. The definition is exactly the same as for the global custom defined functions, each module may defined its own: - `systemBooleanFunctions` - `customBooleanFunctions` - `systemScalarFunctions` - `customScalarFunctions` - `systemObservableFunctions` - `systemAggregatedBooleanFunctions` - `systemAggregatedScalarFunctions` ```ts [[1,3, "moduleExpressionFunctions"], [2,4, "Alert"], [3,5, "customBooleanFunctions"], [3,6, "THIS_BUSINESS_YEAR"], [4,18, "CalculatedColumn"], [5,19, "customScalarFunctions"], [5,20, "USD_CONVERT"]] // Expression Options expressionOptions: { moduleExpressionFunctions: { Alert: { customBooleanFunctions: { THIS_BUSINESS_YEAR: { handler(args: any[], context: ExpressionContext) { const startBusinessYear = new Date(2023, 4, 1); return new Date(args[0]) > startBusinessYear; }, returnType: 'boolean', description: 'Returns true if Date is in current Business year', signatures: ['THIS_BUSINESS_YEAR(dateToCheck: Date)'], examples: ['THIS_BUSINESS_YEAR([tradeDate])'], } } }, CalculatedColumn: { customScalarFunctions: { USD_CONVERT: { handler(args, context: ExpressionContext) { const inputValue: number = args[0]; if (isNaN(inputValue)) { return undefined; } const oldCurrency = args[1]; if (oldCurrency === 'USD') { return inputValue; } if (oldCurrency === 'EUR') { return inputValue * 1.15; } else if (oldCurrency === 'GBP') { return inputValue * 1.2; } return undefined; }, description: 'Converts EUR & GBP Currencies to Dollar', signatures: ['USD_CONVERT(val: number, ccy: string)'], examples: [ 'USD_CONVERT([value],[currency])', 'USD_CONVERT([value], "GBP")', ], } } } } } ``` **Example: AdapTableQL: Custom Functions Scope** Adding Scope to Custom Expression Functions - This example creates the same 2 Custom Expression Functions in the demo above. - However it uses the `moduleExpressionFunctions` property to limit where they can be applied (as explained in the Step by Step Guide above): - the `THIS_BUSINESS_YEAR` Custom Boolean Expression Function is available only in the `Alert` Module - the `USD_CONVERT` Custom Scalar Expression Function is available only in the `Calculated Column` Module ### Expand to see the Definitions provided ```ts expressionOptions: { moduleExpressionFunctions: { Alert: { customBooleanFunctions: { THIS_BUSINESS_YEAR: { handler(args: any[], context: ExpressionContext) { const startBusinessYear = new Date(2023, 4, 1); return new Date(args[0]) > startBusinessYear; }, returnType: 'boolean', description: 'Returns true if Date is in current Business year', signatures: ['THIS_BUSINESS_YEAR(dateToCheck: Date)'], examples: ['THIS_BUSINESS_YEAR([tradeDate])'], }, }, }, CalculatedColumn: { customScalarFunctions: { USD_CONVERT: { handler(args, context: ExpressionContext) { const inputValue: number = args[0]; if (isNaN(inputValue)) { return undefined; } const oldCurrency = args[1]; if (oldCurrency === 'USD') { return inputValue; } if (oldCurrency === 'EUR') { return inputValue * 1.15; } else if (oldCurrency === 'GBP') { return inputValue * 1.2; } return undefined; }, description: 'Converts EUR & GBP Currencies to Dollar', signatures: [ 'USD_CONVERT(currentValue: number, currentCurrency: string)', ], examples: [ 'USD_CONVERT([value],[currency])', 'USD_CONVERT([value], "GBP")', ], }, }, }, }, }, ``` - Open the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) and see the 2 custom Expression Functions in the Functions Dropdown - `THIS_BUSINESS_YEAR` should be available only in the `Alert` Module - `USD_CONVERT` should be available only in the `CalculatedColumn` Module ```ts import {AdaptableOptions, ExpressionContext} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom Expression Functions Scope', expressionOptions: { moduleExpressionFunctions: { Alert: { customBooleanFunctions: { THIS_BUSINESS_YEAR: { handler(args: any[], context: ExpressionContext) { const startBusinessYear = new Date(2023, 4, 1); return new Date(args[0]) > startBusinessYear; }, returnType: 'boolean', description: 'Returns true if Date is in current Business year', signatures: ['THIS_BUSINESS_YEAR(dateToCheck: Date)'], examples: ['THIS_BUSINESS_YEAR([tradeDate])'], }, }, }, CalculatedColumn: { customScalarFunctions: { USD_CONVERT: { handler(args, context: ExpressionContext) { const inputValue: number = args[0]; if (isNaN(inputValue)) { return undefined; } const oldCurrency = args[1]; if (oldCurrency === 'USD') { return inputValue; } if (oldCurrency === 'EUR') { return inputValue * 1.15; } else if (oldCurrency === 'GBP') { return inputValue * 1.2; } return undefined; }, description: 'Converts EUR & GBP Currencies to Dollar', signatures: [ 'USD_CONVERT(currentValue: number, currentCurrency: string)', ], examples: [ 'USD_CONVERT([value],[currency])', 'USD_CONVERT([value], "GBP")', ], }, }, }, }, }, initialState: { Dashboard: { PinnedToolbars: ['GridFilter'], ModuleButtons: ['CalculatedColumn', 'SettingsPanel'], }, Theme: {CurrentTheme: 'dark'}, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-purchased', Scope: { ColumnIds: ['purchased'], }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'yyyy/MM/dd', }, }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: ['item', 'amount', 'currency', 'purchased'], AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {ColDef} from 'ag-grid-enterprise'; export const columnDefs: ColDef[] = [ { headerName: 'id', field: 'Id', filter: true, editable: false, sortable: true, cellDataType: 'text', }, { headerName: 'Item', field: 'item', filter: true, editable: false, sortable: true, cellDataType: 'text', }, { headerName: 'Amount', field: 'amount', filter: true, editable: true, sortable: true, cellDataType: 'number', }, { headerName: 'Currency', field: 'currency', filter: true, editable: true, sortable: true, cellDataType: 'text', }, { headerName: 'Purchased', field: 'purchased', filter: true, editable: true, sortable: true, cellDataType: 'date', }, ]; ``` ```ts export const rowData = [ { id: 1, item: 'Washing Machine', amount: 500.35, currency: 'EUR', purchased: new Date(2023, 5, 11), }, { id: 2, item: 'Football', amount: 2.7, currency: 'GBP', purchased: new Date(2022, 7, 19), }, { id: 3, item: 'Fridge', amount: 385.75, currency: 'USD', purchased: new Date(2021, 4, 5), }, { id: 4, item: 'Food', amount: 195, currency: 'CHF', purchased: new Date(2021, 3, 15), }, { id: 5, item: 'Holiday', amount: 1187.5, currency: 'GBP', purchased: new Date(2019, 8, 7), }, { id: 6, item: 'Misc', amount: 56.23, currency: 'EUR', purchased: new Date(2023, 4, 5), }, { id: 7, item: 'Laptop', amount: 2500, currency: 'EUR', purchased: new Date(2022, 8, 3), }, { id: 8, item: 'Sport Tickets', amount: 904, currency: 'EUR', purchased: new Date(2019, 2, 24), }, { id: 9, item: 'Clothes', amount: 480.25, currency: 'USD', purchased: new Date(2023, 5, 29), }, { id: 10, item: 'Concert Ticket', amount: 235.45, currency: 'USD', purchased: new Date(2023, 7, 15), }, { id: 11, item: 'Rent', amount: 652.75, currency: 'GBP', purchased: new Date(2021, 4, 23), }, ]; ``` --- # Standard Custom Expression Functions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom-standard - Standard Custom Expression Functions are evaluated on a per-row basis - The return type is a single value Standard Custom Expression Functions are [Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) which are: - provided by developers at design-time - operate on a single row a time during evaluation Although, the return type can be any value, AdapTable divides them into 2 groups for ease of use: - Boolean Expression Functions - return true / false value - Scalare Expression Functions - return any value ## How It Works The process of defining, using and evaluation a Custom Expression Function is as follows: - A developer defines an Expression Function - it includes various properties including a `handler` function - Many of the properties are 'convenience' ones which provide help and examples - These are designed to aid the user when accessing the function in the Expression Editor - The Expression Function is then treated like any other Function and is included in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) - A run-time User includes the Expresssion Function in an Expression (this can be done in Initial State also) - AdapTableQL invokes the `handler` function when it evaluates the Expression and returns the correct value ### Defining a Custom Expression Function In this Guide we will create 2 Custom Expressions: - a Boolean Function - `THIS_BUSINESS_YEAR` - which will return true or false - a Scalar Function - `USD_CONVERT` - which returns a number Add the function to relevant section in ExpressionOptions: - boolean functions: `customBooleanFunctions` - scalar functions: `customScalarFunctions` Both types are a Record with 2 properties: - keys: custom function names - values: of type [`ExpressionFunction`](https://www.adaptabletools.com/docs/reference/expressionfunction.md) By convention, the Function name is in CAPITAL LETTERS - to make it more readable when used in an Expression. The `handler` property is the most important property, providing the actual implementation of the Function. It receives `args` array (of type any[]) and `context` property (type [`ExpressionContext`](https://www.adaptabletools.com/docs/reference/expressioncontext.md)) and returns a Boolean. Set the `returnType` of the function This is particularly important for boolean Expressions The Description is designed to help a User accessing the Function in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) It should explain what the Function does There are 2 extra properties that can provide context sensitive help to users accessing the Custom Function: - `signatures`: Shows how the Function should be called - `examples`: Small examples of Function in action ```ts [[1,3, "customBooleanFunctions"], [1,15, "customScalarFunctions"], [2,4, "THIS_BUSINESS_YEAR"], [2,16, "USD_CONVERT"], [3,5, "handler"],[3,17, "handler"], [4,9, "returnType"],[4,34, "returnType"], [5,10, "description"], [5,35, "description"], [6,11, "signatures"],[6,36, "signatures"], [6,12, "examples"], [6,37, "examples"]] // Expression Options expressionOptions: { customBooleanFunctions: { THIS_BUSINESS_YEAR: { handler(args: any[], context: ExpressionContext) { const startBusinessYear = new Date(2023, 4, 1); return new Date(args[0]) > startBusinessYear; }, returnType: 'boolean', description: 'Returns true if Date is in current Business year', signatures: ['THIS_BUSINESS_YEAR(dateToCheck: Date)'], examples: ['THIS_BUSINESS_YEAR([tradeDate])'], }, }, customScalarFunctions: { USD_CONVERT: { handler(args, context: ExpressionContext) { const inputValue: number = args[0]; if (isNaN(inputValue)) { return undefined; } const oldCurrency = args[1]; if (oldCurrency === 'USD') { return inputValue; } if (oldCurrency === 'EUR') { return inputValue * 1.15; } else if (oldCurrency === 'GBP') { return inputValue * 1.2; } return undefined; }, returnType: 'number', description: 'Converts EUR & GBP Currencies to Dollar', signatures: ['USD_CONVERT(val: number, ccy: string)'], examples: [ 'USD_CONVERT([value],[currency])', 'USD_CONVERT([value], "GBP")', ], }, }, } ``` ## Expression Function Object Each Standard Custom Expression function is an instance of an [`ExpressionFunction`](https://www.adaptabletools.com/docs/reference/expressionfunction.md) object. ### Anatomy of an Expression Function The full definition of the [`ExpressionFunction`](https://www.adaptabletools.com/docs/reference/expressionfunction.md) used when creating a Custom Expression Function is as follows: | Property | Type | Description | | --- | --- | --- | | [category](https://www.adaptabletools.com/docs/reference/expressionfunction.md#category) | [`ExpressionCategory`](https://www.adaptabletools.com/docs/reference/expressioncategory.md) | Used to group Functions Expression Editor dropdown | | [description](https://www.adaptabletools.com/docs/reference/expressionfunction.md#description) | `string` | What the AdaptableQL Function does | | [examples](https://www.adaptabletools.com/docs/reference/expressionfunction.md#examples) | `string[]` | Examples that demonstrate the AdaptableQL Function | | [handler](https://www.adaptabletools.com/docs/reference/expressionfunction.md#handler) | [`ExpressionFunctionHandler`](https://www.adaptabletools.com/docs/reference/expressionfunctionhandler.md) | Actual AdaptableQL Function called by the Expression (mandatory prop) | | [hasEagerEvaluation](https://www.adaptabletools.com/docs/reference/expressionfunction.md#haseagerevaluation) | `boolean` | Whether Expression is evaluated without handling inner AST nodes | | [icon](https://www.adaptabletools.com/docs/reference/expressionfunction.md#icon) | [`AdaptableIcon`](https://www.adaptabletools.com/docs/reference/adaptableicon.md)` \| \{ text: string; \}` | Icon to show for the function (e.g. in ColumnFilter operator dropdown and QueryBuilder) | | [isAvailable](https://www.adaptabletools.com/docs/reference/expressionfunction.md#isavailable) | [`AdaptableModule`](https://www.adaptabletools.com/docs/reference/adaptablemodule.md)`[] \| ((context: `[`ExpressionFunctionAvailabilityContext`](https://www.adaptabletools.com/docs/reference/expressionfunctionavailabilitycontext)`) => boolean)` | Where the function is available. `undefined` (default) means available in **all** modules; an `AdaptableModule[]` restricts availability to the listed modules; a callback decides dynamically per (function, module). | | [isHiddenFromMenu](https://www.adaptabletools.com/docs/reference/expressionfunction.md#ishiddenfrommenu) | `boolean` | Removes entry from Expression Editor's Functions dropdown | | [label](https://www.adaptabletools.com/docs/reference/expressionfunction.md#label) | `string` | Human-friendly display name for the function / operator, shown in operator pickers such as the ColumnFilter operator dropdown. When omitted it falls back to the function's registered name (its id). | | [operands](https://www.adaptabletools.com/docs/reference/expressionfunction.md#operands) | `Overload[]` | Operand type matrix that drives how the function is rendered in the visual QueryBuilder (the evolution of `inputs` + `returnType`). Its presence opts the function into the visual builder. | | [returnType](https://www.adaptabletools.com/docs/reference/expressionfunction.md#returntype) | `'boolean' \| 'number' \| 'string' \| 'date' \| 'null' \| 'any'` | Type returned by Function: boolean, number, string, date, any | | [rhs](https://www.adaptabletools.com/docs/reference/expressionfunction.md#rhs) | `OperatorRhsSlot[]` | Optional, sparse, positional configuration for the NON-SUBJECT operands (the RHS for operators; all args for value sources). Index 0 is the first non-subject operand. Anything omitted uses the QueryBuilder conventions (all operand sources allowed; column-aware value editor for text/number, free editor for date/boolean). | | [shortcuts](https://www.adaptabletools.com/docs/reference/expressionfunction.md#shortcuts) | `string[]` | Quick Filter bar keystroke(s) that select this operator (e.g. `['=']`, `['#', '[']`). Only meaningful for boolean operators used in the ColumnFilter. Can be overridden per column via `columnFilterOptions.quickFilterWildcards`. | | [signatures](https://www.adaptabletools.com/docs/reference/expressionfunction.md#signatures) | `string[]` | How the AdaptableQL Function should be called | | [subject](https://www.adaptabletools.com/docs/reference/expressionfunction.md#subject) | `'none'` | Boolean operators only. Drops the lefthand subject (rare; e.g. `ANY_CONTAINS`). Default: the operator has a subject. Value sources (`returnType !== 'boolean'`) never have a subject regardless. | This object contains many properties, including `handler` which performs the actual evaluation. It's advisable to provide the other properties as it greatly helps run-time users accessing the function in an Expression ### Expression Function `handler` As noted above, `handler` is the key (and only **mandatory**) property as is performs the actual evaluation. It takes the form of a function which receives 2 parameters (`args` and `context`) and returns any value. ### Understanding the handler property The `handler` property in an [`ExpressionFunction`](https://www.adaptabletools.com/docs/reference/expressionfunction.md) is of type [`ExpressionFunctionHandler`](https://www.adaptabletools.com/docs/reference/expressionfunctionhandler.md) and has the signature: ```ts export type ExpressionFunctionHandler = (args: any[], context: ExpressionContext) => any; ``` As can be seen, it receives 2 parameters: - `args` - whichever arguments, if any, the handler requires in order to perform the evaluation - `context` - an [`ExpressionContext`](https://www.adaptabletools.com/docs/reference/expressioncontext.md) providing general information about the current node and where and how the Expression is being performed; it's full definition is: | Property | Type | Description | | --- | --- | --- | | [cellValueOverride](https://www.adaptabletools.com/docs/reference/expressioncontext.md#cellvalueoverride) | `\{ columnId: string; value: unknown; \}` | Substitutes the value returned for one column reference — used when a single cell / array element is being evaluated rather than the whole row (e.g. Badge Style per-element rules). Honoured by `COL` / `[columnId]` and, when it targets the scope column, `$SCOPE()`. | | [columnScope](https://www.adaptabletools.com/docs/reference/expressioncontext.md#columnscope) | `string` | Column scope for the expression (if applicable). Technically this is a Column ID | | [dataChangedEvent](https://www.adaptabletools.com/docs/reference/expressioncontext.md#datachangedevent) | [`CellDataChangedInfo`](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md) | Changed cell data | | [evaluateCustomQueryVariable](https://www.adaptabletools.com/docs/reference/expressioncontext.md#evaluatecustomqueryvariable) | `(functionName: string, args?: any[]) => any` | Evaluate custom variables | | [filterFn](https://www.adaptabletools.com/docs/reference/expressioncontext.md#filterfn) | `(any: any) => boolean` | Optional filter function to be applied before evaluating the expression | | [functions](https://www.adaptabletools.com/docs/reference/expressioncontext.md#functions) | [`ExpressionFunctionMap`](https://www.adaptabletools.com/docs/reference/expressionfunctionmap.md)`` | All Expression Functions available to AdaptableQL | | [getRowNodes](https://www.adaptabletools.com/docs/reference/expressioncontext.md#getrownodes) | `() => IRowNode[]` | Get custom list rows | | [namedQueryCallStack](https://www.adaptabletools.com/docs/reference/expressioncontext.md#namedquerycallstack) | `string[]` | All Named Query evaluations: tracked in order to detect circular dependencies | | [node](https://www.adaptabletools.com/docs/reference/expressioncontext.md#node) | `IRowNode` | Current AG Grid Row Node being evaluated | | [pivotResultColumn](https://www.adaptabletools.com/docs/reference/expressioncontext.md#pivotresultcolumn) | `Column` | Pivot Result Column when evaluating a Pivoted Column | | [whereClauseFunctions](https://www.adaptabletools.com/docs/reference/expressioncontext.md#whereclausefunctions) | [`ExpressionFunctionMap`](https://www.adaptabletools.com/docs/reference/expressionfunctionmap.md)`` | Expression Functions available to AdaptableQL in (optional) WHERE clause | | [adaptableContext](https://www.adaptabletools.com/docs/reference/expressioncontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | Most of these properties will not be of interest when writing a custom expression function. However the `node` property is often useful - it is the AG Grid Row Node where the evaluation is taking place. **Example: AdapTableQL: Custom Scalar Functions** Using Custom Scalar Expression Functions - This example creates 2 Custom Scalar Expression Functions - used in a table showing (random) purchases: - a `THIS_BUSINESS_YEAR` Custom Boolean Expression Function - returns true if Date is in current Business Year (after 1 April) - a `USD_CONVERT` Custom Scalar Expression Function - fictitiously converts USD and GBP prices to Dollars - We then reference each of these Expression Functions in other Modules: - `THIS_BUSINESS_YEAR` in a [Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) which puts matching rows in Bold, Italics and a Blue Font - `USD_CONVERT` in the `Dollar Price` [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - Both Custom Expressions in the `Old High Exchange` [Named Query](https://www.adaptabletools.com/docs/handbook-named-queries/index.md) ### Expand to see the Definitions provided The 2 Custom Expression Functions are defined as follows: ```ts expressionOptions: { customBooleanFunctions: { THIS_BUSINESS_YEAR: { handler(args: any[], context: ExpressionContext) { const startBusinessYear = new Date(2023, 4, 1); return new Date(args[0]) > startBusinessYear; }, returnType: 'boolean', description: 'Returns true if Date is in current Business year', signatures: ['THIS_BUSINESS_YEAR(dateToCheck: Date)'], examples: ['THIS_BUSINESS_YEAR([tradeDate])'], }, }, customScalarFunctions: { USD_CONVERT: { handler(args, context: ExpressionContext) { const inputValue: number = args[0]; if (isNaN(inputValue)) { return undefined; } const oldCurrency = args[1]; if (oldCurrency === 'USD') { return inputValue; } if (oldCurrency === 'EUR') { return inputValue * 1.15; } else if (oldCurrency === 'GBP') { return inputValue * 1.2; } return undefined; }, description: 'Converts EUR & GBP Currencies to Dollar', signatures: ['USD_CONVERT(val: number, ccy: string)'], examples: [ 'USD_CONVERT([value],[currency])', 'USD_CONVERT([value], "GBP")', ], }, }, }, ``` And they are referenced elsewhere: ```ts NamedQuery: { NamedQueries: [ { Name: 'Old High Exchange', BooleanExpression: 'USD_CONVERT(1, [currency]) > 1.175 AND !THIS_BUSINESS_YEAR([purchased])', }, ], }, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'dollar_price', FriendlyName: 'Dollar Price', Query: { ScalarExpression: 'USD_CONVERT([amount], [currency])'}, CalculatedColumnSettings: { DataType: 'number', }, }, ], }, FormatColumn: { FormatColumns: [ { Style: { FontWeight: 'Bold', FontStyle: 'Italic', ForeColor: 'LightBlue', }, Scope: { All: true, }, Rule: { BooleanExpression: 'THIS_BUSINESS_YEAR([purchased])', }, }, ], }, ``` - Open the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) and see the 2 custom Expression Functions in the Functions Dropdown ```ts import {AdaptableOptions, ExpressionContext} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom Expression Functions', expressionOptions: { customBooleanFunctions: { THIS_BUSINESS_YEAR: { handler(args: any[], context: ExpressionContext) { const startBusinessYear = new Date(2023, 4, 1); return new Date(args[0]) > startBusinessYear; }, returnType: 'boolean', description: 'Returns true if Date is in current Business year', signatures: ['THIS_BUSINESS_YEAR(dateToCheck: Date)'], examples: ['THIS_BUSINESS_YEAR([tradeDate])'], category: 'Custom', }, }, customScalarFunctions: { USD_CONVERT: { handler(args, context: ExpressionContext) { const inputValue: number = args[0]; if (isNaN(inputValue)) { return undefined; } const oldCurrency = args[1]; if (oldCurrency === 'USD') { return inputValue; } if (oldCurrency === 'EUR') { return inputValue * 1.15; } else if (oldCurrency === 'GBP') { return inputValue * 1.2; } return undefined; }, description: 'Converts EUR & GBP Currencies to Dollar', signatures: [ 'USD_CONVERT(currentValue: number, currentCurrency: string)', ], examples: [ 'USD_CONVERT([value],[currency])', 'USD_CONVERT([value], "GBP")', ], category: 'Custom', }, }, }, editOptions: { showSelectCellEditor: context => { return context.column.columnId === 'currency'; }, customEditColumnValues: context => { if (context.column.columnId === 'currency') { return [ {label: 'GBP', value: 'GBP'}, {label: 'EUR', value: 'EUR'}, {label: 'USD', value: 'USD'}, {label: 'CHF', value: 'GCHFBP'}, ]; } return context.defaultValues; }, }, initialState: { Dashboard: { PinnedToolbars: ['GridFilter'], ModuleButtons: ['FormatColumn', 'CalculatedColumn', 'SettingsPanel'], }, NamedQuery: { NamedQueries: [ { Name: 'Old High Exchange', BooleanExpression: 'USD_CONVERT(1, [currency]) > 1.175 AND !THIS_BUSINESS_YEAR([purchased])', }, ], }, Theme: {CurrentTheme: 'dark'}, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'dollar_price', FriendlyName: 'Dollar Price', Query: { ScalarExpression: 'USD_CONVERT([amount], [currency])', }, CalculatedColumnSettings: { DataType: 'number', }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-dollar_price', Scope: { ColumnIds: ['dollar_price'], }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { FractionDigits: 2, Prefix: '$', }, }, Style: { Alignment: 'Right', }, }, { Name: 'formatColumn-purchased', Scope: { ColumnIds: ['purchased'], }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'yyyy/MM/dd', }, }, }, { Name: 'style-all', Style: { FontWeight: 'Bold', FontStyle: 'Italic', ForeColor: 'LightBlue', }, Scope: { All: true, }, Rule: { BooleanExpression: 'THIS_BUSINESS_YEAR([purchased])', }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'item', 'amount', 'currency', 'purchased', 'dollar_price', ], AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {ColDef} from 'ag-grid-enterprise'; export const columnDefs: ColDef[] = [ { headerName: 'id', field: 'Id', filter: true, editable: false, sortable: true, cellDataType: 'text', }, { headerName: 'Item', field: 'item', filter: true, editable: false, sortable: true, cellDataType: 'text', }, { headerName: 'Amount', field: 'amount', filter: true, editable: true, sortable: true, cellDataType: 'number', }, { headerName: 'Currency', field: 'currency', filter: true, editable: true, sortable: true, cellDataType: 'text', }, { headerName: 'Purchased', field: 'purchased', filter: true, editable: true, sortable: true, cellDataType: 'date', }, ]; ``` ```ts export const rowData = [ { id: 1, item: 'Washing Machine', amount: 500.35, currency: 'EUR', purchased: new Date(2023, 5, 11), }, { id: 2, item: 'Football', amount: 2.7, currency: 'GBP', purchased: new Date(2022, 7, 19), }, { id: 3, item: 'Fridge', amount: 385.75, currency: 'USD', purchased: new Date(2021, 4, 5), }, { id: 4, item: 'Food', amount: 195, currency: 'CHF', purchased: new Date(2021, 3, 15), }, { id: 5, item: 'Holiday', amount: 1187.5, currency: 'GBP', purchased: new Date(2019, 8, 7), }, { id: 6, item: 'Misc', amount: 56.23, currency: 'EUR', purchased: new Date(2023, 4, 5), }, { id: 7, item: 'Laptop', amount: 2500, currency: 'EUR', purchased: new Date(2022, 8, 3), }, { id: 8, item: 'Sport Tickets', amount: 904, currency: 'EUR', purchased: new Date(2019, 2, 24), }, { id: 9, item: 'Clothes', amount: 480.25, currency: 'USD', purchased: new Date(2023, 5, 29), }, { id: 10, item: 'Concert Ticket', amount: 235.45, currency: 'USD', purchased: new Date(2023, 7, 15), }, { id: 11, item: 'Rent', amount: 652.75, currency: 'GBP', purchased: new Date(2021, 4, 23), }, ]; ``` ## Defining Custom Expression Functions As noted above Custom Expression functions can be of 2 return types: - Boolean - used in Grid Filter, Conditional Styles, Reports etc. and return a true / false value - Scalar - used in [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) and can have any return type ### Boolean Expression Functions The `customBooleanFunctions` property is used to define custom __Boolean__ Expression Functions: ### `customBooleanFunctions` Custom Boolean Expression Functions available in AdapTableQL Property which lists any Custom Boolean Expression Functions to be added to AdapTableQL. The property returns either: - a Record of type string and Expression Function - a JavaScript function which returns the same ```ts customBooleanFunctions?: | Record | ((context: GlobalExpressionFunctionsContext) => Record); ``` ### Scalar Expression Functions The `customScalarFunctions` property is used to define __Scalar__ Expression Functions: ### `customScalarFunctions` Custom Scalar Expression Functions available in AdapTableQL Property which lists any Custom Scalar Expression Functions to be added to AdapTableQL. The property returns either: - a Record of type string and Expression Function - a JavaScript function which returns the same ```ts customScalarFunctions?: | Record | (( context: GlobalExpressionFunctionsContext ) => Record); ``` --- # Observable Expression Functions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-observable - This section lists all the Observable Expression Functions shipped with [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) - They are used when creating Observble Expressions There are 4 Expression Functions available when writing [Observable Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-observable/index.md) | Function | Example | Watches for Changes | | ----------- | ----------------------------------------------- | ----------------------------- | | GRID_CHANGE | ```GRID_CHANGE(MIN([col1]), TIMEFRAME('1h'))``` | Whole Grid in given timeframe | | ROW_CHANGE | ```ROW_CHANGE(MAX([col1]), TIMEFRAME('30s'))``` | Each row in given timeframe | | ROW_ADDED | ```ROW_ADDED()``` | New row is added to Grid | | ROW_REMOVED | ```ROW_REMOVED(3, TIMEFRAME('5m'))``` | Row is removed from Grid | Observable Functions typically receive 2 arguments: - Change Type - what type of change for - Timeframe - time period in which to observe changes ## Change Type The Change Type in an Observable Expression describes the type of Change that AdapTable observes. - Most of these Change Type functions accept the name of the Column as the sole parameter - The `COUNT` change type also receives a number to indicate the number of changes to observe | Function | Example | Description | | -------- | ---------------------------------- | ---------------------------------------------------- | | MIN | ```GRID_CHANGE(MIN([col1])``` | Smallest change of note in the specified column | | MAX | ```ROW_CHANGE(MAX([col1])``` | Largest change of note in the specified column | | NONE | ```ROW_CHANGE(NONE([col1])``` | No changes have ocurred in the specified column | | COUNT | ```GRID_CHANGE(COUNT([col1], 3)``` | Given no. of changes ocurred in the specified column | ## Timeframe The `TIMEFRAME` function sets how long AdapTable should observe changes: | Function | Example | Description | | --------- | ----------------------------------------------- | ----------------------------- | | TIMEFRAME | ```ROW_CHANGE(MIN([col1]), TIMEFRAME('20m'))``` | Timeframe for observed change | ## Where The `WHERE` function keyword can be used with Observable Expressions to limit the Scope of what is being observed: | Function | Example | Description | | -------- | ------------------------------------------------------------------- | ---------------------------------------------- | | WHERE | ```GRID_CHANGE(MIN([col1]), TIMEFRAME('1h')) WHERE [col12]='USD'``` | Narrows the scope of the Observable Expression | --- # Relative Change Expression Functions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-relative-change - This section lists the Relative Changed Expression Functions shipped with [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) - These are primarily used when creating Alerts or Flashing Cell Rules There are 3 Expression Functions available when writing [Relative Change Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-relative-change/index.md) | Function | Example | Watches for Changes | | --------------- | ------------------------------- | ---------------------------------- | | ANY_CHANGE | ```ANY_CHANGE([col1)``` | The Column's value has changed | | PERCENT_CHANGE | ```PERCENT_CHANGE([col1) > 5``` | Column has changed by given % | | ABSOLUTE_CHANGE | ```ABSOLUTE([col1) > 5``` | Column has changed by given amount | --- # Standard Expression Functions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-standard - This page lists all the Expression Functions shipped by AdapTable that return a single value - We have divided them into Boolean and Scalar for convenience sake Most Expression Functions return a single value. These can be divided into 2 conceptual groups: - **Boolean** Expression Functions: return a true / false value - **Scalar** Expression Functions: return any single value All of these functions can be used in **any type of Expression** ## Boolean Expression Functions These are Expression Functions that return a true / false value. The 6 most common Boolean functions are available in shortcut form (e.g.`=` instead of `EQ`) | Function | Shortcut | Example | Returns True If | | --------------- | -------- | ------------------------------------------- | ------------------------------------- | | EQ | = | ```[col1]=5``` *or* ```EQ([col1], 5)``` | Both inputs are equal | | NEQ | != | ```[col1]!=5``` *or* ```NEQ([col1], 5)``` | Both inputs are NOT equal | | GT | `>` | ```[col1] > 5``` *or* ```GT([col1], 5)``` | Input1 `>` Input2 | | LT | `<` | ```[col1] < 5``` *or* ```LT([col1], 5)``` | Input1 `<` Input2 | | GTE | `>=` | ```[col1] >= 5``` *or* ```GTE([col1], 5)``` | Input1 `>=` Input2 | | LTE | `<=` | ```[col1] <= 5``` *or* ```LTE([col1], 5)``` | Input1 `<=` Input2 | | AND | | ```[col1] > 5 AND [col2] > 10``` | Both statements are true | | OR | | ```[col1] > 5 OR [col2] > 10``` | Either statement is true | | NOT | | ```!([col1] > 5)``` | Negation of statement is true | | BETWEEN | | ```BETWEEN(5, [col1], [col2])``` | Input1 between Input2 & Input3 | | IN | | ```[col1] IN (5, 10, 17)``` | Any input value is in inputted column | | CONTAINS | | ```CONTAINS([col1], 's' )``` | Input1 contains Input2 | | STARTS_WITH | | ```STARTS_WITH([col1], 's' )``` | Input1 starts with Input2 | | ENDS_WITH | | ```ENDS_WITH([col1], 's' )``` | Input1 ends with Input2 | | ANY_CONTAINS | | ```ANY_CONTAINS('abc')``` | Any column contains input | | IS_BLANK | | ```IS_BLANK([col1])``` | Input value is empty | | IS_NOT_BLANK | | ```IS_NOT_BLANK([col1])``` | Input value is not empty | | IS_NUMERIC | | ```IS_NUMERIC([col1])``` | Input value is a number | | REGEX | | ```REGEX([col1, pattern])``` | Input value matches pattern as Regex | | IS_HOLIDAY | | ```IS_HOLIDAY([col1)``` | Input value is a Holiday | | IS_WORKDAY | | ```IS_WORKDAY([col1)``` | Input value is a Working Day | ## Scalar Expression Functions These are Expression Functions that return a single value of any type (though its most commonly numeric). | Function | Shortcut | Example | Returns | | ----------- | -------- | ------------------------------------------ | ------------------------------------------ | | ADD | + | ```[col1] + 5``` *or* ```ADD([col1], 5)``` | Sum of inputted numbers | | SUB | - | ```[col1] - 5``` *or* ```SUB([col1], 5)``` | Number2 minus Number1 | | MUL | * | ```[col1] * 5``` *or* ```MUL([col1], 5)``` | Product of inputted numbers | | DIV | / | ```[col1] / 5``` *or* ```DIV([col1], 5)``` | Division of inputted numbers | | MOD | % | ```[col1] % 5``` *or* ```MOD([col1], 5)``` | Modulo of 2 numbers | | POW | ^ | ```[col1] ^ 5``` *or* ```POW([col1], 5)``` | Pow of 2 numbers | | MIN | | ```MIN([col1], 5)``` | Smallest of inputted numbers | | MAX | | ```MAX([col1], 5)``` | Highest of inputted numbers | | AVG | | ```AVG([col1], 5)``` | Average of inputted numbers | | ABS | | ```ABS([col1])``` | Abs value of inputted number | | CEILING | | ```CEILING([col1])``` | Smallest integer `>=` inputted number | | FLOOR | | ```FLOOR([col1])``` | Largest integer `<=` inputted number | | ROUND | | ```ROUND([col1])``` | Rounds number to nearest integer | | DATE | | ```DATE('20210101')``` | New Date using input value | | NOW | | ```[col1] > NOW()``` | The current Date | | CURRENT_DAY | | ```[col1] > CURRENT_DAY()``` | The current Day | | DAY | | ```DAY([col1]) = DAY(NOW())``` | The Day (from a Date) | | WEEK | | ```WEEK([col1]) = WEEK(NOW())``` | The Week (from a Date) | | MONTH | | ```MONTH([col1]) = MONTH(NOW())``` | The Month (from a Date) | | YEAR | | ```YEAR([col1]) = YEAR(NOW())``` | The Year (from a Date) | | ADD_DAYS | | ```[col1] < ADD_DAYS(NOW(), 5)``` | Date using input data & Days to add | | ADD_WEEKS | | ```[col1] < ADD_WEEKS(NOW(), 5)``` | Date using input data & Weeks to add | | ADD_MONTHS | | ```[col1] < ADD_MONTHS(NOW(), 5)``` | Date using input data & Months to add | | ADD_YEARS | | ```[col1] < ADD_YEARS(NOW(), 5)``` | Date using input data & Years to add | | DIFF_DAYS | | ```DIFF_DAYS([col], NOW() )``` | Difference in Days between 2 Dates | | DIFF_WEEKS | | ```DIFF_WEEKS([col], NOW() )``` | Difference in Weeks between 2 Dates | | DIFF_MONTHS | | ```DIFF_MONTHS([col], NOW() ))``` | Difference in Months between 2 Dates | | DIFF_YEARS | | ```DIFF_YEARS([col], NOW() )``` | Difference in Years between 2 Dates | | SUB_STRING | | ```SUB_STRING([col1],1,5)``` | New string extracted from given string | | REPLACE | | ```REPLACE([col1],'GBP','EUR')``` | String with matching chars replaced | | COALESCE | | ```COALESCE([col1],[col2],[col3])``` | First input value which is not null | | LEN | | ```LEN([col1])``` | Number of characters in a string | | UPPER | | ```UPPER([col1])``` | Input string to Upper Case | | LOWER | | ```LOWER([col1])``` | Input string to Lower Case | | CONCAT | | ```CONCAT([col1],[col2],[col3])``` | Concatenation of input strings | | TO_ARRAY | | ```TO_ARRAY(col1],[col2],[col3])``` | Array using the inputted arguments | | NULL | | ```NULL``` | NULL literal, intentional absence of value | --- # Reducing Expression Complexity Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-managing - AdapTable allows developers to reduce the AdapTableQL functionality on offer to users - This is often the case if you are evaluating Expressions yourself externally instead of using AdapTableQL - In particular 2 features are provided: - Make some Expression Functions unavailable in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) and for AdapTableQL evaluation - Specify that certain Columns cannot be included in Expressions AdapTable provides a couple of helpful features to reduce the complexity of the Expressions available to users. This is particularly useful if [ you are evaluating Expressions on the Server](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md) using your own translation ## Limiting Available AdapTableQL Functions By default **all** [Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) are available in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) and available for the AdapTableQL evaluation engine. Multiple properties in [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md) can be used to limit the functions which the user can access. Similarly developers can [limit which Predicates are available](https://www.adaptabletools.com/docs/handbook-column-filter-configuring/index.md#limiting-system-filters) in Filters These can be divided into 2 groups: - Limit by Function Type - Limit by Module ### Limit By Function Type To limit Expressions globally for __each distinct Function Expression Type__ use: - `systemBooleanFunctions` - `systemScalarFunctions` - `systemObservableFunctions` - `systemAggregatedBooleanFunctions` - `systemAggregatedScalarFunctions` ### How to limit provided Expression Functions Each property has to be evaluated to a list of Expression Type specific function names: - either directly by defining a list of functions - or by defining a function callback which, using the provided context, evaluates to a list of functionss For instance to omit 3 Boolean Functions and 1 Scalar Function you would do: ```ts {4,7} import {Adaptable, AdaptableQL } from '@adaptabletools/adaptable'; expressionOptions:{ systemBooleanFunctions: AdaptableQL.BooleanFunctions.filter( (functionName) => functionName !== 'BETWEEN' && functionName !== 'NOT' && functionName !== 'CONTAINS' ), systemScalarFunctions: (context: GlobalExpressionFunctionsContext) => context.availableExpressionFunctionNames.filter((functionName) => functionName !== 'ADD'), }; ``` All System functions are available through the publicly exported `AdaptableQL` constant or in the callback context ### `systemBooleanFunctions` Which Boolean Expression Functions are available [`BooleanFunctionName[]`](https://www.adaptabletools.com/docs/reference/booleanfunctionname.md) Specifies which Boolean Expression Functions can be used in AdapTableQL and be available in the Expression Editor. The values listed should be of type [`BooleanFunctionName`](https://www.adaptabletools.com/docs/reference/booleanfunctionname.md): ```ts // Omit 3 Boolean Functions expressionOptions:{ systemBooleanFunctions: AdaptableQL.BooleanFunctions.filter( (functionName) => functionName !== 'BETWEEN' && functionName !== 'NOT' && functionName !== 'CONTAINS' ), // OR, ALTERNATIVELY systemBooleanFunctions: (context: GlobalExpressionFunctionsContext) => context.availableExpressionFunctionNames.filter( (functionName) => functionName !== 'BETWEEN' && functionName !== 'NOT' && functionName !== 'CONTAINS' ), }; ``` ### `systemScalarFunctions` Which Scalar Expression Functions are available [`ScalarFunctionName[]`](https://www.adaptabletools.com/docs/reference/scalarfunctionname.md) Specifies which Scalar Expression Functions can be used in AdapTableQL and be available in the Expression Editor. The values listed should be of type [`ScalarFunctionName`](https://www.adaptabletools.com/docs/reference/scalarfunctionname.md): ```ts // Omit 3 Scalar Functions expressionOptions:{ systemScalarFunctions: AdaptableQL.ScalarFunctions.filter( (functionName) => functionName !== 'ADD' && functionName !== 'MIN' && functionName !== 'MAX' ), // OR, ALTERNATIVELY systemScalarFunctions: (context: GlobalExpressionFunctionsContext) => context.availableExpressionFunctionNames.filter( (functionName) => functionName !== 'ADD' && functionName !== 'MIN' && functionName !== 'MAX' ), }; ``` ### `systemObservableFunctions` Which Observable Expression Functions are available [`ObservableFunctionName[]`](https://www.adaptabletools.com/docs/reference/observablefunctionname.md) Specifies which Observable Expression Functions can be used in AdapTableQL and be available in the Expression Editor. The values listed should be of type [`ObservableFunctionName`](https://www.adaptabletools.com/docs/reference/observablefunctionname.md): ```ts // Omit the WHERE Observable Function expressionOptions:{ systemScalarFunctions: AdaptableQL.ObservableFunctions.filter( (functionName) => functionName !== 'WHERE' ), // OR, ALTERNATIVELY systemScalarFunctions: (context: GlobalExpressionFunctionsContext) => context.availableExpressionFunctionNames.filter( (functionName) => functionName !== 'WHERE' ), }; ``` ### `systemAggregatedBooleanFunctions` Which Aggregated Boolean Expression Functions are available [`AggregatedBooleanFunctionName[]`](https://www.adaptabletools.com/docs/reference/aggregatedbooleanfunctionname.md) Specifies which Aggregated Boolean Expression Functions can be used in AdapTableQL and be available in the Expression Editor. The values listed should be of type [`AggregatedBooleanFunctionName[]`](https://www.adaptabletools.com/docs/reference/aggregatedbooleanfunctionname.md): ```ts // Omit the AVG Aggregated Boolean Function expressionOptions:{ systemAggregatedBooleanFunctions: AdaptableQL.AggregatedBooleanFunctions.filter( (functionName) => functionName !== 'AVG' ), // OR, ALTERNATIVELY systemAggregatedBooleanFunctions: (context: GlobalExpressionFunctionsContext) => context.availableExpressionFunctionNames.filter( (functionName) => functionName !== 'AVG' ), }; ``` ### `systemAggregatedScalarFunctions` Which Aggregated Scalar Expression Functions are available [`AggregatedScalarFunctionName[]`](https://www.adaptabletools.com/docs/reference/aggregatedscalarfunctionname.md) Specifies which Aggregated Scalar Expression Functions can be used in AdapTableQL and be available in the Expression Editor. The values listed should be of type [`AggregatedScalarFunctionName[]`](https://www.adaptabletools.com/docs/reference/aggregatedscalarfunctionname.md): ```ts // Omit the MIN & MAX Observable Functions expressionOptions:{ systemAggregatedBooleanFunctions: AdaptableQL.AggregatedScalarFunctions.filter( (functionName) => functionName !== 'MIN' && functionName !== 'MAX' ), // OR, ALTERNATIVELY systemAggregatedBooleanFunctions: (context: GlobalExpressionFunctionsContext) => context.availableExpressionFunctionNames.filter( (functionName) => functionName !== 'MIN' && functionName !== 'MAX' ), }; ``` ### Limit By Module To limit Expressions on a **per Module** basis use `moduleExpressionFunctions` in [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md). ### `moduleExpressionFunctions` Which Expressions Functions are available - specified by Module [`ModuleExpressionFunctions`](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctions.md) This property specifies which AdapTableQL Expression Functions are available in Adaptable on a per **Module** basis. The property is defined as follows: ``` moduleExpressionFunctions?: | ModuleExpressionFunctionsMap | ((context: ModuleExpressionFunctionsContext) => ModuleExpressionFunctions | undefined); ``` As can be seen the property can be evaluated in one of 2 ways: Directly returning a Map This approach returns a [`ModuleExpressionFunctionsMap`](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctionsmap.md). This is a Record with the Adaptable Modules as property keys and the specific Expression Functions as property values Via a function The function receives a `ModuleExpressionFunctionsContext` property and returns the [`ModuleExpressionFunctions`](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctions.md) The [`ModuleExpressionFunctionsContext`](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctionscontext.md) property is defined as follows: | Property | Type | Description | | --- | --- | --- | | [availableAggregatedBooleanFunctionNames](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctionscontext.md#availableaggregatedbooleanfunctionnames) | [`AggregatedBooleanFunctionName`](https://www.adaptabletools.com/docs/reference/aggregatedbooleanfunctionname.md)`[]` | The global aggregated boolean expression functions | | [availableAggregatedScalarFunctionNames](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctionscontext.md#availableaggregatedscalarfunctionnames) | [`AggregatedScalarFunctionName`](https://www.adaptabletools.com/docs/reference/aggregatedscalarfunctionname.md)`[]` | The global aggregated scalar expression functions | | [availableBooleanFunctionNames](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctionscontext.md#availablebooleanfunctionnames) | [`BooleanFunctionName`](https://www.adaptabletools.com/docs/reference/booleanfunctionname.md)`[]` | The global boolean expression functions | | [availableObservableFunctionNames](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctionscontext.md#availableobservablefunctionnames) | [`ObservableFunctionName`](https://www.adaptabletools.com/docs/reference/observablefunctionname.md)`[]` | The global observable expression functions | | [availableScalarFunctionNames](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctionscontext.md#availablescalarfunctionnames) | [`ScalarFunctionName`](https://www.adaptabletools.com/docs/reference/scalarfunctionname.md)`[]` | The global scalar expression functions | | [module](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctionscontext.md#module) | [`AdaptableModule`](https://www.adaptabletools.com/docs/reference/adaptablemodule.md) | The Adaptable Module requesting the expression functions | | [adaptableContext](https://www.adaptabletools.com/docs/reference/moduleexpressionfunctionscontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```ts {5,8,15,18} // Exclude observable functions 'ROW_CHANGE' from Alert Module // and exclude scalar functions 'LOWER' and 'UPPER' from Calculated Column // add custom scalar function LATEST_PRICE to Calculated Column expressionOptions:{ moduleExpressionFunctions: (context: ModuleExpressionFunctionsContext) => { if (context.module === 'Alert') { return { systemObservableFunctions: context.availableObservableFunctionNames.filter( (functionName) => functionName !== 'ROW_CHANGE' ) }; } if (context.module === 'CalculatedColumn') { return { systemScalarFunctions: context.availableScalarFunctionNames.filter( (functionName) => functionName !== 'LOWER' && functionName !== 'UPPER' ), customScalarFunctions: { LATEST_PRICE: { handler(args, context) { const tradeStatus = context.node.data['tradeStatus']; return tradeStatus == 'active' ? priceService.getLatestPrice(args[0]) : context.node.data['closingPrice']; }, description: 'Returns latest price for an Instrument from a Server', signatures: ['LATEST_PRICE(instrument: string)'], examples: ['LATEST_PRICE([ticker])'], }, } }; } }, }; ``` - Functions defined in `moduleExpressionFunctions` __inherit & override__ functions defined globally in `systemXFunctions` - e.g. if the `Alert` module only provides customised `systemObservableFunctions`, it inherits all other system functions (`systemBooleanFunctions`, `systemScalarFunctions`, etc.) **Example: AdapTableQL: Limiting Functions** Removes some System AdapTableQL Expression Functions ### Expand to see the Expressions removed ```ts {3,10,16,22} expressionOptions: { // globally defined functions systemScalarFunctions: ( context: GlobalExpressionFunctionsContext ) => context.availableExpressionFunctionNames.filter( functionName => functionName !== 'ADD' ), // module specific functions moduleExpressionFunctions: ( context: ModuleExpressionFunctionsContext ) => { if (context.module === 'CalculatedColumn') { return { // the `availableScalarFunctionNames` are the ones defined above, in `expressionOptions.systemScalarFunctions` systemScalarFunctions: context.availableScalarFunctionNames.filter( functionName => functionName !== 'LOWER' && functionName !== 'UPPER' ), }; } // ALL other modules will inherit the functions defined globally }, }, ``` ```ts import { AdaptableOptions, ScalarFunctionName, GlobalExpressionFunctionsContext, ModuleExpressionFunctionsContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Limiting Expression Functions', expressionOptions: { systemScalarFunctions: ( context: GlobalExpressionFunctionsContext ) => context.availableExpressionFunctionNames.filter( functionName => functionName !== 'ADD' ), moduleExpressionFunctions: (context: ModuleExpressionFunctionsContext) => { if (context.module === 'CalculatedColumn') { return { // the `availableScalarFunctionNames` are the ones defined above, in `expressionOptions.systemScalarFunctions` systemScalarFunctions: context.availableScalarFunctionNames.filter( functionName => functionName !== 'LOWER' && functionName !== 'UPPER' ), }; } // ALL other modules will inherit the functions defined globally return undefined; }, }, initialState: { Dashboard: { PinnedToolbars: ['GridFilter'], ModuleButtons: ['CalculatedColumn', 'SettingsPanel'], }, 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, }, ], }, }, }; ``` ## Limiting Queryable Columns By default all Columns in AdapTable can be used in a Query. To specify whether or not a given column is Queryable, provide an implementation for the `isColumnQueryable` property of [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md). ### `isColumnQueryable` Whether a Column should be included in AdapTableQL Expressions Custom function which specifies if a Column should be included in AdapTableQL Expressions. This is often used in conjunction with the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) to reduce the complexity of an Expression The function receives a [`QueryableColumnContext`](https://www.adaptabletools.com/docs/reference/queryablecolumncontext.md) object (which simply contains the Column) and returns a boolean: If you want **all** columns in the Grid to be available, do not provide an implementation for this function ```ts // Don't allow Date columns to be queryable expressionOptions:{ isColumnQueryable: (queryableColumnContext: QueryableColumnContext) => { return queryableColumnContext.adaptableColumn.dataType != 'date' }, }; ``` If no implementation is provided, all Columns can be used in Expressions Use `filter` and `floatingFilter` properties in GridOptions to set which Columns can be **filtered** **Example: AdapTableQL: Limiting Columns** Set some columns to be non queryable - In this example we have provided an implementation for the `isColumnQueryable` property to prevent these columns from being used in Expressions: - The `License` Column - All `Date` Columns ### Expand to see how Queryable Columns were set ```ts expressionOptions: { isColumnQueryable: (queryableColumnContext: QueryableColumnContext) => { return ( queryableColumnContext.adaptableColumn.dataType != 'date' && queryableColumnContext.adaptableColumn.columnId != 'license' ); }, }, ``` - Open the Expression Editor (e.g. by clicking the arrows in the Query toolbar) and note that License and all Date Columns are absent from the Column list ```ts import { AdaptableOptions, QueryableColumnContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Limiting Queryable Columns', expressionOptions: { isColumnQueryable: (queryableColumnContext: QueryableColumnContext) => { return ( queryableColumnContext.column.dataType != 'date' && queryableColumnContext.column.columnId != 'license' ); }, }, initialState: { Dashboard: { PinnedToolbars: ['GridFilter'], }, 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, }, ], }, }, }; ``` --- # Observable Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-observable - Observable Expressions watch for changes (or lack of changes) in data that match a particular pattern - They do this by utilising advanced __reactive techniques (RX)__ - When the expression evaluates to `TRUE`, AdapTable can perform a specified action. - The [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) Module supports Observable Expressions - Queries that contain an Observable Expression can and optionally a include a BooleanExpression Observable Expressions watch for data changes that match a particular pattern. They can also be used to watch for a **lack** of changes This is accomplished by leveraging advanced Reactive (Rx) techniques. Observable Expressions are currently only used in [Observable Alerts](https://www.adaptabletools.com/docs/handbook-alerting-observables/index.md) Observable Expressions may contain any of [Boolean Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md#boolean-functions), [Scalar Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md#scalar-functions) or [Observable Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md#observable-functions). ## Observable Functions There are 4 main Observable Functions available in an Observable Expression: ### `ROW_CHANGE` This observes changes in each **row** in isolation - essentially there is one observer per row. If using [WHERE](#where-clause) then only those rows which match the clause will be observed This allows users to create Alerts saying "tell me if any Row performs a particular change 3 times". ### `GRID_CHANGE` This observes changes in the entire **grid**. This allows users to create Alerts saying 'tell me if nothing in the Grid changes for 5 minutes". If using [WHERE](#where-clause) then only the subset of rows which match the clause will be observed ### `ROW_ADDED` This observes when new Rows have been added to the Grid. It can take no arguments (any Row is added) or a Count and / or a Timeframe. ### `ROW_REMOVED` This observes when new Rows have been added to the Grid. It can take no arguments (any Row is removed) or a Count and / or a Timeframe. ## Observable Function Parameters Each Observable Function has 2 mandatory parameters: ### `TIMEFRAME` The timeframe is the period of time in which the Observable operates. This may be defined as a number of: - seconds (e.g. `30s`) - minutes (e.g. `15m`) - hours (e.g. `8h`) ### `CHANGE_TYPE` This defines the **type** of change that is being observed by AdapTable. `CHANGE_TYPE` **always** takes a single parameter which is of type [Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) Change Type is not used for `ROW_ADDED` and `ROW_REMOVED` observables There are 4 different Change Types available: - `MIN` - its the smallest change of note in the specified column - `MAX` - its the largest change of note in the specified column - `NONE` - no changes have occurred in the specified column - `COUNT` - a given amount of changes have occurred in the specified column `COUNT` requires an additional numeric param, specifying how many changes are required to fulfill the Expression ### Examples ***Tell Me When...*** ```ts [[1, 2, "ROW_CHANGE"], [2, 2, "COUNT"], [3, 2 , "TIMEFRAME"]] // The ItemCount value in a Row changes 3 times within a 5 minute timeframe ROW_CHANGE( COUNT( [ItemCount], 3) , TIMEFRAME('5m') ) ``` ```ts [[1, 2, "ROW_CHANGE"], [2, 2, "MAX"], [3, 2 , "TIMEFRAME"]] // An Order Cost cell contains its highest value within the last hour ROW_CHANGE( MAX( [OrderCost] ), TIMEFRAME('1h') ) ``` ```ts [[1, 2, "GRID_CHANGE"], [2, 2, "NONE"], [3, 2 , "TIMEFRAME"]] // The Price column has not ticked - in any row in the Grid - for the last 30 seconds GRID_CHANGE( NONE( [Price] ), TIMEFRAME('30s') ) ``` ```ts [[1, 2, "ROW_ADDED"]] // A Row has been added to the Grid ROW_ADDED() ``` ```ts [[1, 2, "ROW_REMOVED"], [2, 2, "3"], [3, 2 , "TIMEFRAME"]] // 3 Rows have been removed from the Grid in the last 5 minutes ROW_REMOVED(3, TIMEFRAME('5m') ) ``` ## `WHERE` Clause Optionally, a __`WHERE`__ clause may be appended to the Observable Expression. This is a [Standard Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) which narrows down the scope of the 'main' part of the Expression. ```ts [[1, 2, "ROW_CHANGE"], [2, 2, "COUNT"], [3, 2 , "TIMEFRAME"], [4, 2, "WHERE"]] // The ItemCount value in a Row changes 3 times within a 5 minute timeframe for Active Trades ROW_CHANGE( COUNT([ItemCount], 3), TIMEFRAME('5m')) WHERE [Status] = 'Active' ``` ```ts [[1, 2, "GRID_CHANGE"], [2, 2, "NONE"], [3, 2 , "TIMEFRAME"], [4, 2, "WHERE"]] // No change has occurred in last 15 minutes in the Price column for rows where currency is dollar GRID_CHANGE( NONE([Price]), TIMEFRAME('15m')) WHERE [Currency] = 'USD' ``` ## Configuring TimeFrame Size ### `maxTimeframeSize` Maximum time (in milliseconds) to hold a Data Change event in a trailing timeframe This property is used in Observable Expressions - see observableExpressionFunctions. The value is capped at 86400000 (i.e. 24 hours) for performance reasons. ```ts {3} // Hold Data Changes for 12 hours expressionOptions:{ maxTimeframeSize: 43200000, }; ``` --- # Quantile (Aggregation) Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-quantile - Creating buckets (e.g. Quartiles, Percentiles) using the `QUANT` function In Quantile Expressions, each value in a column is placed into a different **bucket** based on its value relative to others in the group. Quantile Expressions are, like Cumulative Expressions, a special case of [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) ## Standard Quantile Expressions It is achieved using the `QUANT` Expression Function - which receives 2 arguments: - the value (typically provided as a Column name) being evaluated - the number of buckets to create ```ts [[1, 2, "QUANT"], [2, 2, "10"]] // Put each PnL into 10 buckets QUANT([PnL], 10) ``` ```ts [[1, 2, "QUANT"], [2, 2, "5"]] // Put each Price into 5 buckets QUANT([Price], 5) ``` ### Quartile & Percentile AdapTable provides 2 additional Expression Functions to be used in the most comment Quantile use cases. `QUARTILE` and `PERCENTILE` will automatically create 4 and 10 buckets respectively. There is no need to add an "amount" argument when using these Functions ```ts [[1, 2, "QUARTILE"]] // Automatically put each PnL into 4 buckets QUARTILE([PnL]) ``` ```ts [[1, 2, "PERCENTILE"]] // Automatically put each Price into 100 buckets PERCENTILE([Price]) ``` **Example: AdapTableQL: Quantile Aggregation** Using Quantile Scalar Aggregation Expressions - This Example demonstrates how to use the `QUANT` Expression Function to calculate Quantile functions - It contains 100 Tickers each with a `Value` (from 1-100 in ascending order) and an associated `Type` - 4 [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) are defined: - `Quartile` - divides the 100 Ticker Values into 4 groups - using `QUARTILE` function - `Quintile` - divides the 100 Ticker Values into 5 groups - using `QUANT` function - `Decile` - divides the 100 Ticker Values into 10 groups - using `QUANT` function - `Percentile` - divides the 100 Ticker Values into 100 groups (so there is therefore just 1 value per group) - using `PERCENTILE` function - Change some Values and note how this changes all the Quantiles it is placed in ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {TickerItem} from './rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'Id', adaptableId: 'Quantile Expressions', 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', ], AutoSizeColumns: true, }, ], }, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'Quartile', Query: { AggregatedScalarExpression: 'QUARTILE([Value])', }, 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: 'PERCENTILE([Value])', }, CalculatedColumnSettings: { DataType: 'number', }, }, ], }, }, }; ``` ```ts import {ColDef} from 'ag-grid-enterprise'; import {TickerItem} from './rowData'; 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 interface TickerItem { Ticker: string; Value: number; Id: number; Type: string; } export const rowData: TickerItem[] = [ { 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', }, ]; ``` ## Grouped Quantile Expressions As with other Aggregation Expressions, you can use the `GROUP_BY` keyword to **group** the Quantile by type. When this happens, AdapTableQL will create a set of buckets for each distinct element returned by `GROUP_BY` ```ts [[1, 2, "QUANT"], [2, 2, "5"], [3, 2, "Currency"]] // Create 5 buckets (Quintile) for each Currency and place the PnL QUANT([PnL], 5, GROUP_BY([Currency])) ``` ```ts [[1, 2, "QUANT"], [2, 2, "10"], [3, 2, "Counterparty"]] // For each distinct Counterparty create 10 buckets (Decile) and place the Price QUANT([Price], 10, GROUP_BY([Counterparty])) ``` **Example: AdapTableQL: Grouped Quantile Aggregation** Using Grouped Quantile Scalar Aggregation Expressions - This Example is similar to the one above and contains the same 4 [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) each using `QUANT` - But it adds a 5th Calculated Column - `Grouped by Type` - which leverages the `GROUP_BY` keyword - The column creates 3 buckets for each set of Values grouped by 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 distinct Type ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {TickerItem} from './rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'Id', adaptableId: 'Grouped Quantile Expressions', 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', ], AutoSizeColumns: true, }, ], }, 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'; import {TickerItem} from './rowData'; 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 interface TickerItem { Ticker: string; Value: number; Id: number; Type: string; } export const rowData: TickerItem[] = [ { 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', }, ]; ``` --- # Relative Change Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-relative-change - Relative Change Expressions evaluate the type of change made to a cell's data - All are boolean and return true if the change meets the desired criteria - They are available in the Flashing Cell and Alert Modules Relative Change Expressions examine the nature of changes made to a cell's data. AdapTableQL provides 3 [Relative Change Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-relative-change/index.md) to deal with different use cases: - `ANY_CHANGE` - `ABSOLUTE_CHANGE` - `PERCENT_CHANGE` ## Any Change The `ANY_CHANGE` function checks if any change whatsoever has been made to a cell's value. This is commonly used when setting up [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) ```ts [[1, 2, "ANY_CHANGE"]] // A data change of any value has been made to the Price Column ANY_CHANGE([PRICE]) ``` ## Absolute Change The `ABSOLUTE_CHANGE` function is used when you want to check if the change is of a certain amount. It most commonly takes a (numeric) Column as the first argument. The Column must be numeric as the evaluation only works on numeric values ```ts [[1, 2, "ABSOLUTE_CHANGE"]] // Value in the Price Column has changed by more than 10 ABSOLUTE_CHANGE([PRICE]) > 10 ``` It is possible to use "INCREASE" to limit the evaluation to changes where new value goes up... ```ts [[1, 2, "ABSOLUTE_CHANGE"], [2, 2, "'INCREASE'"]] // Value in the Price Column has increased by more than 10 ABSOLUTE_CHANGE([PRICE], 'INCREASE') > 10 ``` ...or "DECREASE" to limit the evaluation to changes where new values goes down ```ts [[1, 2, "ABSOLUTE_CHANGE"], [2, 2, "'DECREASE'"]] // Value in the Price Column has decreased by 5 ABSOLUTE_CHANGE([PRICE], 'DECREASE') = 5 ``` ## Percent Change The `PERCENT_CHANGE` function is similar to `ABSOLUTE_CHANGE`, but used to evaluate the relative change in value. It most commonly takes a (numeric) Column as the first argument. The Column must be numeric as the evaluation only works on numeric values ```ts [[1, 2, "PERCENT_CHANGE"]] // Value in the Price Column has changed by more than 10% PERCENT_CHANGE([PRICE]) > 10 ``` Again, you can use "INCREASE" to limit the evaluation to upward percentage changes... ```ts [[1, 2, "PERCENT_CHANGE"], [2, 2, "'INCREASE'"]] // Value in the Price Column has increased by more than 50% PERCENT_CHANGE([PRICE], 'INCREASE') > 50 ``` ...or "DECREASE" to limit the evaluation to downward percentage changes ```ts [[1, 2, "PERCENT_CHANGE"], [2, 2, "'DECREASE'"]] // Value in the Price Column has decreased by 10% PERCENT_CHANGE([PRICE], 'DECREASE') = 10 ``` See [Relative Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-relative-change/index.md) for more details and a demo showing how these functions can be used --- # Standard Expressions Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-standard - A Standard Expression is evaluated against each row in isolation and returns a single value. - The return value of a Standard Expression can be of 2 types: - **any** (i.e. scalar) data type - used in the [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) Module. - **boolean** (i.e. true / false ) - most common type of Expression, available in many Modules (e.g. Alerts, Grid Filter) - Although Expressions have potential to be extremely complex, essentially they consist of just (up to) 4 elements: - Columns - e.g. `BloombergBid`, `MarkitBid` - Expression Functions (e.g. MIN) - some of which can be displayed as Operators (e.g. `<`) - Logical Operators - (enable multiple clauses via `AND` or `OR`) - Input Values - e.g. 50 A Standard Expression is evaluated against **each row in isolation** and returns **a single value**. The return value can be (conceptually) divided in 2 groups: - **scalar** (i.e. any data type) - **boolean** (ie. true / false) - returns `true` for each row which passes **all** conditions in the Expression Standard Expressions are used in these Modules: | Module | Usage | Type | | -------------------------------------------------------------------------- | ----------------------------------------------------------- | ------- | | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) | Triggers an Alert when data change matches a Rule | Boolean | | [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) | Evaluates the value displayed in the column | Scalar | | [Export](https://www.adaptabletools.com/docs/handbook-exporting/index.md) | Custom Reports export only those rows returned by the Query | Boolean | | [Flashing Cell](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) | Whether to Flash the Cell (or Row) | Boolean | | [Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) | Sets whether or not to show the Format Column | Boolean | | [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) | Returns rows which match the true / false condition | Boolean | | [Plus Minus](https://www.adaptabletools.com/docs/handbook-editing-plus-minus/index.md) | Manages evaluation of Custom Nudge Values | Boolean | AdapTableQL provides more complex [Aggregated Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) where the evaluation includes multiple rows ## Elements in Standard Expressions Expressions can be very complex but essentially they are made of up 4 distinct elements: 1. Columns (or Fields) 2. Expression Functions (and Operators) 3. AND / OR Logical Operators 4. Input Values - An Expression can include as many functions, operators, columns and values as are required - Not every element is present in every Expression In this page we will analyse each of these 4 Elements in turn, marking each type of Element with the relevant number when providing code example. - As we will see, strictly speaking there are really only 2 Elements: Expression Functions and Input Values - Columns & Logical Operators are also Expressions Functions, but treated separately here for easier comprehension Let's start with a small Example which shows all 4 elements of an Expression. Imagine we want a [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) so that AdapTable only displays rows where either of 2 clauses is true: - whichever value was the smaller in the `BloombergBid` and `MarkitBid` columns, was greater than 50 - the `Currency` column has a value of Dollar That could be written with the following (boolean) Expression: ```ts [[2, 1, "MIN"], [1, 1, "BloombergBid"], [1, 1, "MarkitBid"],[2, 1, ">"],[4, 1, "50"],[3, 1, "OR"], [1, 1, "Currency"], [4, 1, "USD"]] MIN([BloombergBid], [MarkitBid]) > 50 OR [Currency] = 'USD' ``` **Example: AdapTableQL: Standard Expressions** Using Standard Expressions in AdapTable - This demo shows a number of different Standard Expressions: - We have 4 Boolean Expressions applied to different AdapTable Modules: - A [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) is filtering the grid for rows where `Language` is *JavaScript* - The [Export](https://www.adaptabletools.com/docs/handbook-exporting/index.md) module contains an `MIT Report` that exports rows where `License` is *MIT License* - A [Format Column Condition](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) is applied to rows where `Github Stars` > 50,000 - An [Alert](https://www.adaptabletools.com/docs/handbook-alerting/index.md) fires when the Rule is triggered that `Open Issues` > 50 - Additionally it contains a Scalar Expression applied to a [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - `Full Github` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Standard Expressions', initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['GridFilter', 'Export', 'Alert'], }, ], ModuleButtons: ['SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export', 'Alert', 'GridFilter'], }, ], }, Theme: {CurrentTheme: 'dark'}, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'full_Github', FriendlyName: 'Full Github', Query: { ScalarExpression: '[github_stars] * [github_watchers]', }, CalculatedColumnSettings: { DataType: 'number', }, }, ], }, Export: { CurrentReport: 'MIT Report', CurrentFormat: 'JSON', Reports: [ { Name: 'MIT Report', ReportColumnScope: 'ScopeColumns', ReportRowScope: 'ExpressionRows', Scope: { ColumnIds: ['name', 'language', 'topics', 'license', 'updated_at'], }, Query: { BooleanExpression: " [license] = 'MIT License'", }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'style-all', Style: { BackColor: '#00ffff', ForeColor: 'Black', }, Scope: { All: true, }, Rule: { BooleanExpression: '[github_stars] > 50000 ', }, }, ], }, Alert: { AlertDefinitions: [ { Name: 'alert-Warning-42', MessageType: 'Warning', Scope: { All: true, }, Rule: { BooleanExpression: '[open_issues_count] > 50 ', }, AlertProperties: { DisplayNotification: true, }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'open_issues_count', 'license', 'github_watchers', 'github_stars', 'full_Github', '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', GridFilter: { Expression: '[language]="JavaScript" ', }, AutoSizeColumns: true, }, ], }, }, }; ``` Now lets at look of each of these 4 Elements in turn. ## 1. Columns This refers to any [Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) whose value is required in the Expression. - A Column is *optional* in Standard Expressions - but one is generally used - Some Observable and Aggregation Expressions require a Column in order for the Expression to be valid When evaluating the Expression, AdapTableQL automatically retrieves the value for the column for each row. Columns are typically referenced by providing the `columnId` in square brackets: ```ts [[1, 2, "Price"],[4, 2, "100"]] // Reference Price Column (in Scalar Expression) [Price] * 100 ``` ```ts [[1, 2, "Currency"],[4, 2, "USD"]] // Reference Currency Column (in Boolean Expression) [Currency] = 'USD' ``` There is no limit to the amount of Columns that can be included in an Expression: ```ts [[2, 2, "MUL"],[1, 2, "OrderCost"],[1, 2, "ItemCost"],[1, 2, "PackageCost"]] // Multiply 3 columns together MUL([OrderCost] , [ItemCost], [PackageCost]) ``` Columns can be used in Scalar Expressions: ```ts [[1, 2, "OrderChange"], [1, 2, "PackageCost"], [1, 2, "OrderCost"],[1, 2, "InvoicedCost"]] // Order Change (minus combined total of PackageCost and OrderCost and Invoiced Cost) [OrderChange] - ([PackageCost] + [OrderCost] + [InvoicedCost]) ``` Or in Boolean Expressions: ```ts [[1, 2, "OrderChange"], [1, 2, "PackageCost"], [1, 2, "OrderCost"],[1, 2, "InvoicedCost"]] // Order Change (minus combined total of PackageCost and OrderCost) differs to Invoiced Cost [OrderChange] - ([PackageCost] + [OrderCost]) != [InvoicedCost] ``` ### Using `COL` Function Columns are actually specialised [Expression Functions](#2-expression-functions) made more readable for user convenience. Therefore they can alternatively be referenced using the `COL` function with the Column name in parentheses: ```ts [[2, 2, "COL"], [1, 2, "Price"],[4, 2, "100"]] // Reference Price Column using COL keyword COL("Price") * 100 ``` ```ts [[2, 2, "COL"], [1, 2, "Currency"],[4, 2, "USD"]] // Reference Currency Column using COL keyword COL("Currency") = 'USD' ``` ### Referencing Columns in Expressions To guarantee Column uniqueness, Expressions use the column's field name. In other words the Expression will reference the **identifier** for the column used by AG Grid. For example it will use `[orderId]` rather than any Caption / Header which was provided (e.g. 'Order Id') - To help identify the column, AdapTable provides the Column's Header in the Column List in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) - There is also an option to see the field / identifier value for the Column instead ### Using Column Friendly Names By default, wherever an Expression is referenced in AdapTable but is not being directly edited - e.g. when displayed in the Settings Panel - the Column's Header is always used. If this is not required behaviour, set `displayColumnFriendlyNamesForExpressions` to *false* in Expression Options ### `displayColumnFriendlyNamesForExpressions` Reference a Column's Header in all Expression overviews (instead of ColumnId) By default whenever AdapTable shows the content of an Expression it will refer to a Column using its `Header` value. This is the property (also known as FriendlyName) used whenever the Column is referred to in the UI and Wizards. The Expression itself stores the Column's `ColumnId` property - since that is guaranteed to be unique. The `ColumnId` property value is what is displayed in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) Set this option to `false` to ensure that the ColumnId property is used everywhere that the Expression is referenced. ```ts {3} // Always use the ColumnId property value when providing details of the Expression const adaptableOptions: AdaptableOptions = { expressionOptions:{ displayColumnFriendlyNamesForExpressions: false } } ``` ### Fields It is possible, if required, to reference a **Field** instead of a Column. A Field is a [row data item](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-row-data/index.md) which is present in the data source, but which is not also a Column. ```ts [[2, 2, "FIELD"], [1, 2, "'Price'"],[4, 2, "100"]] // use FIELD keyword to reference Price item in data source, even though its not a Column FIELD('Price') * 100 ``` With Fields you **have** to explicitly use the `FIELD` Expression Function - the square brackets shortcut is not available ## 2. Expression Functions At the core of each Expression are **Expression Functions**. These are useful functions that are shipped with AdapTableQL which cover a multitude of use cases. - Consult the [AdapTableQL Expression List](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) for full details of all the Expression Functions available in AdapTableQL - See [Reducing Expression Complexity](https://www.adaptabletools.com/docs/adaptable-ql-expression-managing/index.md) for details on how to remove some AdapTable-shipped Expresssion Functions If an Expression Function you would like to use is missing, please email Adaptable Tools Support with suggested details Almost every Expression includes an Expression Function - though sometimes, as we will see below - they can be look like simple Operators. Observable and Aggregation Expressions **require** Expression Functions in order to be valid There is no limit on the number of Expression Functions allowed in an Expression. For example this basic Boolean Expression contains 2 Expression Functions: (It also contains 2 [Columns](#1-columns), the `OR` [Logical Operator](#3-logical-operators), the `>` [Operator](#2-expression-functions) and 2 [Input Values](#4-input-values)) - `STARTS_WITH` Boolean Expression Function - `MIN` Scalar Expression Function ```ts [[2, 1, "STARTS_WITH"], [2, 1, "MIN"]] STARTS_WITH([col1], 'ABC') OR MIN([col2], [col3]) > 100 ``` Expression Functions are capitalised and some will require one or more arguments for evaluation. For example to return the average from 3 numbers you can write: ```ts [[2, 1, "AVG"]] AVG(5, 12, 21) ``` Typically Function arguments are dynamic, receiving a current grid cell value (via a Column) as seen above: ```ts [[2, 1, "AVG"], [1, 1, "bloombergBid"], [1, 1, "markitBid"], [1, 1, "indicativeBid"]] AVG([bloombergBid], [markitBid], [indicativeBid]) ``` There are many String manipulation functions available: ```ts [[2, 2, "COALESCE"]] // Return the first non-null column value in a list COALESCE([bloombergPrice], [indicativePrice], [markitPrice]) ``` ```ts [[2, 2, "CONCAT"],[2, 2, "LOWER"],[2, 2, "UPPER"]] // Concatenate employee's name after changing case CONCAT( LOWER([employee_first_name]), UPPER([employee_last_name]) ) ``` And numeric functions: ```ts [[2, 2, "MAX"]] // Return highest of 4 columns MAX ([ItemCost], [OrderCost], [InvoicedCost], ([PackageCost]*10)) ``` And date functions: ```ts [[2, 2, "DIFF_DAYS"],[2, 2, "ADD_DAYS"]] // Use Day diffing and adding functions DIFF_DAYS(CURRENT_DAY(), ADD_DAYS([OrderDate],5) ) > [ChangeLastOrder] ``` ```ts [[2, 2, "ADD_DAYS"]] // Combine Date functions with Ternary Logic [ShippedDate] > ADD_DAYS([OrderDate] , 21) ? 'Delayed' : 'On time' ``` Expression Functions can be combined with Logical Operators: ```ts [[2, 2, "CONTAINS"], [1, 2, "Country"], [4, 2, "United"], [3, 2, "OR"] , [1, 2, "Currency"], [2, 2, "="], [4, 2, "USD"]] // Country contains 'United' OR Currency is Dollar CONTAINS([Country], 'United') OR [Currency] = 'USD' ``` Expression Function arguments can themselves be Expression Functions However, you must make sure that the Expression Function returns the correct Data Type So to run a Scalar Expression which will return a date 5 days from now you can: - use the `ADD_DAYS` function which takes 2 arguments (a date and a number) - use the `CURRENT_DAY` function as the 1st argument - use an input (or Column) value as the 2nd argument ```ts [[2, 2, "ADD_DAYS"], [2, 2, "CURRENT_DAY"], [4, 2, "5"]] // Return the Date, 5 days from now ADD_DAYS(CURRENT_DAY(), 5) ``` And to turn this into a Boolean Expression: ```ts [[2, 2, "ADD_DAYS"], [2, 2, "CURRENT_DAY"], [4, 2, "5"], [2, 2, "<"], [1, 2, "TradeDate"]] // Is TradeDate in next 5 days ADD_DAYS(CURRENT_DAY(), 5) < [TradeDate] ``` In addition to System Expressions Functions, Developers can provide [Custom Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom/index.md) if required ### Operator Shortcuts AdapTable provides a number of of operator shortcuts for the most commonly used Expression Functions. - Similar to Columns, Operators are actually convenient wrappers around [Expression Functions](#2-expression-functions) - For instance `+` is a short-hand for the `ADD` function and `>` is a convenient way of using `GT` These can conceptually be divided into 2 groups: - **Boolean** operators - typically used to compare the 2 parts of an Expression's clause The most commonly boolean operators used are: `=`, `!=`, `>`, `>=`, `<` and `<=`. ```ts [[1, 2, "Price"], [2, 2, ">"],[4, 2, "100"]] // Use Price Column with GreaterThan Operator [Price] > 100 ``` ```ts [[1, 2, "Currency"], [2, 2, "="],[4, 2, "USD"]] // Use Currency Column with Equals Operator [Currency] = 'USD' ``` - **Scalar** operators - typically used to perform maths on 2 (or more) elements in a clause The most commonly used scalar operators are: `+`, `-`, `*`, `/`, and `^`. ```ts [[1, 2, "PackageCost"], [2, 2, "+"], [1, 2, "OrderCost"]] // PackageCost plus OrderCost [PackageCost] + [OrderCost] ``` ```ts [[1, 2, "OrderChange"], [2, 2, "-"], [1, 2, "PackageCost"]] // OrderChange minus PackageCost [OrderChange] - [PackageCost] ``` Because operators are convenient wrappers around [Expression Functions](#2-expression-functions), the 4 Expressions above can be rewritten using Functions in place of the operator: ```ts [[2, 1, "GT"], [1, 1, "Price"],[4, 1, "100"]] GT([Price], 100) ``` ```ts [[2, 1, "EQ"], [1, 1, "Currency"],[4, 1, "USD"]] EQ([Currency], 'USD') ``` ```ts [[2, 1, "ADD"], [1, 1, "PackageCost"], [1, 1, "OrderCost"]] ADD([PackageCost], [OrderCost]) ``` ```ts [[2, 1, "SUB"], [1, 1, "OrderChange"], [1, 1, "PackageCost"]] SUB([OrderChange], [PackageCost]) ``` Expression Functions can therefore be combined with Operators if required. ```ts [[2, 2, "MAX"], [1, 2, "Price"], [1, 2, "Cost"], [2, 2, ">"], [4, 2, "100"]] // Return any row where the Greater of Price and Cost is over 100 MAX([Price], [Cost]) > 100 ``` ### Advanced Expression Functions AdapTable provides some Expression Functions which are designed to be used [in more advanced use cases](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced/index.md): - [QUERY](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-query-function/index.md) - enables Named Queries to be referenced in an Expression: ```ts [[2, 2, "QUERY"]] // Reference the "Big Orders" Named Query QUERY("Big Orders") ``` - [VAR](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-var-function/index.md) - supports custom values in Expressions: ```ts [[2, 2, "VAR"],[1, 2, "country"]] // Reference the VAR named 'VAT' and pass in the Country column as an argument VAR("VAT",[country]) > 1 ``` - [IF](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-logic/index.md) - enables ternary logic to be used in Expressions: ```ts [[1, 2, "[Comments]"], [2, 2, "?"], [4, 2, "Big"], [4, 2, "Small"]] // Return 'Big' if more than 100 Comments, otherwise 'Small' [Comments] > 100 ? 'Big' : 'Small' ``` - [CASE](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-logic/index.md) - faciliates more complex logic in Expressions: ```ts [[2, 2, "CASE"], [1, 2, "[day]"], [2, 2, "WHEN"],[4, 2, "'Saturday'"],[2, 2, "THEN"],[4, 2, "'weekend'"], [2, 2, "ELSE"],[4, 2, "'workday'"], [2, 2, "END"]] // If the Day column contains "Saturday" then return "weekend", otherwise return "workday" CASE [day] WHEN 'Saturday' THEN 'weekend' ELSE 'workday' END ``` Read more about each of these more complex Expression Functions in the [Guide to Advanced Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced/index.md) ## 3. AND / OR Logical Operators All the examples so far have contained one clause to be evaluated by AdapTableQL. However **multiple clauses** can be provided - most typically in a Boolean Expression - via logical operators. Logical operators are themselves [Expression Functions](#2-expression-functions) that we treat separately here for comprehension purposes There are 2 logical operators available when connecting clauses in Expressions: - The `AND` logical operator - requires that **both** clauses in the Expression are true: ```ts [[1, 2, "Price"], [2, 2, ">"], [3, 2, "AND"], [1, 2, "Currency"], [2, 2, "="] ,[4, 2, "USD"]] // Check Price is over 100 AND the Currency is Dollar [Price] > 100 AND [Currency] = 'USD' ``` - The `OR` logical operator - requires that **either** clause in the Expression is true: ```ts [[1, 2, "Price"], [2, 2, ">"], [3, 2, "OR"], [1, 2, "Currency"], [2, 2, "="],[4, 2, "USD"]] // Check Price is over 100 OR the Currency is Dollar [Price] > 100 OR [Currency] = 'USD' ``` ### Using Parentheses There is no limit on the number of clauses in an Expression, nor the number of `AND` or `OR` functions. Where there are multiple clauses it is often advisable to provide parentheses. - Depending on the complexity of the Expression parentheses might be *required* - In any case it is good practice always to use them for (human) readability purposes ```ts [[1, 2, "Price"], [2, 2, ">"], [3, 2, "AND"] , [1, 2, "Currency"], [2, 2, "="], [3, 2, "OR"], [1, 2, "ItemCost"], [2, 2, "<"],[1, 2, "OrderCost"]] // Check Price is over 100 AND either Currency is Dollar or Package Cost is less than Order Cost ([Price] > 100) AND (([Currency] = 'USD') OR ([ItemCost] < [OrderCost])) ``` **Example: AdapTableQL: Multi-Clause Boolean Expressions** Using Boolean Expressions with multiple Clauses - This example includes similar Boolean Expressions to those in the demo above but they all contain multiple clauses joined by `AND` or `OR` - A [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) is filtering the grid for rows where `Language` is *JavaScript* **and** either `Github Watchers` < 20500 **or** `Github Stars` > 8500 - A custom report in [Export](https://www.adaptabletools.com/docs/handbook-exporting/index.md) - `MIT JavaScript` - exports rows where `License` is *MIT License* **and** `Language` is *JavaScript* - A [Format Column Condition](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) is applied to rows where `Github Stars` > 50,000 **or** `License` is *MIT License* - An [Alert](https://www.adaptabletools.com/docs/handbook-alerting/index.md) fires when the Rule is triggered that `Open Issues` > 50 **and** `Language` is *JavaScript* ### Expand to see the multi-clause Boolean Expressions being used ``` Layout: { GridFilter: { Expression: '[language]="JavaScript" AND ([github_watchers] > 20500 OR [github_stars] > 8500)', }, }, Export: { CurrentReport: 'MIT JavaScript', CurrentFormat: 'JSON', Reports: [ { Name: 'MIT JavaScript', ReportColumnScope: 'ScopeColumns', ReportRowScope: 'ExpressionRows', Scope: { ColumnIds: ['name', 'language', 'topics', 'license', 'updated_at'], }, Query: { BooleanExpression: "[language] = 'JavaScript' AND [license] = 'MIT License'", }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'FormatColumn-all-261', Style: { BackColor: '#00ffff', }, Scope: { All: true, }, Rule: { BooleanExpression: "[license] = 'MIT License' OR [github_stars] > 50000 ", }, }, ], }, Alert: { AlertDefinitions: [ { Name: 'alert-Warning-86', MessageType: 'Warning', Scope: { All: true, }, Rule: { BooleanExpression: '[open_issues_count] > 50 AND [language] = "JavaScript"', }, AlertProperties: { DisplayNotification: true, }, }, ], } ``` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Standard Expressions with multiple clauses', initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['GridFilter', 'Export', 'Alert'], }, ], ModuleButtons: ['SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export', 'Alert', 'GridFilter'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'MIT JavaScript', CurrentFormat: 'JSON', Reports: [ { Name: 'MIT JavaScript', ReportColumnScope: 'ScopeColumns', ReportRowScope: 'ExpressionRows', Scope: { ColumnIds: ['name', 'language', 'topics', 'license', 'updated_at'], }, Query: { BooleanExpression: "[language] = 'JavaScript' AND [license] = 'MIT License'", }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'style-all', Style: { BackColor: '#00ffff', ForeColor: 'Black', }, Scope: { All: true, }, Rule: { BooleanExpression: "[license] = 'MIT License' OR [github_stars] > 50000 ", }, }, ], }, Alert: { AlertDefinitions: [ { Name: 'alert-Warning-43', MessageType: 'Warning', Scope: { All: true, }, Rule: { BooleanExpression: '[open_issues_count] > 50 AND [language] = "JavaScript"', }, AlertProperties: { DisplayNotification: true, }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'open_issues_count', 'license', 'github_watchers', 'github_stars', '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', GridFilter: { Expression: '[language]="JavaScript" AND ([github_watchers] > 20500 OR [github_stars] > 8500)', }, AutoSizeColumns: true, }, ], }, }, }; ``` ## 4. Input Values Input Values are hard-coded values provided by the User (rather than being dynamically derived by AdapTableQL from a Grid cell when the Expression evaluates). ```ts [[1, 2, "Price"], [2, 2, ">"], [4, 2, "100"]] // Use Price Column with an Input Value [Price] > 100 ``` ```ts [[1, 2, "Currency"], [2, 2, "="], [4, 2, "USD"]] // Use Currency Column with an Input Value [Currency] = 'USD' ``` There is no requirement to use a Input value - two Columns can be compared instead: ```ts [[1, 2, "tradeDate"], [2, 2, ">"], [1, 2, "settlementDate"]] // Compare 2 columns (with no Input Value) [tradeDate] > [settlementDate] ``` There is no limit on the number of Input Values which can be used in an Expression: ```ts [[1, 2, "Price"], [2, 2, ">"], [4, 2, "100"], [3, 2, "AND"] , [1, 2, "Currency"], [2, 2, "="], [4, 2, "USD"], [3, 2, "OR"], [1, 2, "PackageCost"], [2, 2, "<"],[4, 2, "125"]] // Check Price is over 100 OR the Currency is Dollar [Price] > 100 AND ([Currency] = 'USD' OR [PackageCost] < 125) ``` --- # AdaptableQL Expression Technical Reference Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference - Expression Options contains many properties to configure AdapTableQl and Expressions - The Expression API section of AdapTable API provides run-time access to Expressions ## Expression Options The [`ExpressionOptions`](https://www.adaptabletools.com/docs/reference/expressionoptions.md) section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) contains options for using [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) Expressions: | Property | Type | Description | Default | | --- | --- | --- | --- | | [caseSensitiveExpressions](https://www.adaptabletools.com/docs/reference/expressionoptions.md#casesensitiveexpressions) | `boolean` | Perform case-sensitive text comparisons when evaluating Expressions | false | | [customAggregatedFunctions](https://www.adaptabletools.com/docs/reference/expressionoptions.md#customaggregatedfunctions) | `Record \| ((context: `[`GlobalExpressionFunctionsContext`](https://www.adaptabletools.com/docs/reference/globalexpressionfunctionscontext.md)`) => Record)` | Bespoke Aggregated Expression Functions - to complement those provided by AdapTable | undefined (none) | | [customQueryVariables](https://www.adaptabletools.com/docs/reference/expressionoptions.md#customqueryvariables) | `Record string \| number \| boolean \| Date)>` | Values to be attached to variables so that a single value can easily be expressed multiple times within a query, or quickly changed to affect the results of a query; evaluated synchronously with each expression evaluation | | | [customScalarFunctions](https://www.adaptabletools.com/docs/reference/expressionoptions.md#customscalarfunctions) | `Record \| ((context: `[`GlobalExpressionFunctionsContext`](https://www.adaptabletools.com/docs/reference/globalexpressionfunctionscontext.md)`<`[`ScalarFunctionName`](https://www.adaptabletools.com/docs/reference/scalarfunctionname.md)`>) => Record)` | Bespoke Scalar Expression Functions - to complement those provided by AdapTable. | undefined (none) | | [displayColumnFriendlyNamesForExpressions](https://www.adaptabletools.com/docs/reference/expressionoptions.md#displaycolumnfriendlynamesforexpressions) | `boolean` | Reference a Column's Header (i.e. FriendlyName) in all Expression overviews (instead of ColumnId) | true | | [evaluateAdaptableQLExternally](https://www.adaptabletools.com/docs/reference/expressionoptions.md#evaluateadaptableqlexternally) | `(context: `[`EvaluateExpressionExternallyContext`](https://www.adaptabletools.com/docs/reference/evaluateexpressionexternallycontext.md)`) => boolean` | Whether a Module (or specific expression) should be evaluated by AdapTableQL | All Modules are evaluated by AdapTable | | [fields](https://www.adaptabletools.com/docs/reference/expressionoptions.md#fields) | [`AdaptableField`](https://www.adaptabletools.com/docs/reference/adaptablefield.md)`[] \| ((context: `[`AdaptableFieldContext`](https://www.adaptabletools.com/docs/reference/adaptablefieldcontext.md)`) => `[`AdaptableField`](https://www.adaptabletools.com/docs/reference/adaptablefield.md)`[])` | Fields are items in Data Source that are NOT columns but can be used in Expressions (via FIELD keyword) | | | [isColumnQueryable](https://www.adaptabletools.com/docs/reference/expressionoptions.md#iscolumnqueryable) | `(queryableColumnContext: `[`QueryableColumnContext`](https://www.adaptabletools.com/docs/reference/queryablecolumncontext.md)`) => boolean` | Can a given column be included in Expressions | undefined (all columns can be used in Expressions) | | [isExpressionFunctionAvailable](https://www.adaptabletools.com/docs/reference/expressionoptions.md#isexpressionfunctionavailable) | `(context: `[`GlobalExpressionFunctionAvailabilityContext`](https://www.adaptabletools.com/docs/reference/globalexpressionfunctionavailabilitycontext)`) => boolean` | Whether an Expression Function is available in a given Module. | undefined (all functions have their default availability) | | [maxTimeframeSize](https://www.adaptabletools.com/docs/reference/expressionoptions.md#maxtimeframesize) | `number` | Maximum time (in milliseconds) to hold a Data Change event in a trailing timeframe | 28800000 (~8 hours) | | [performExpressionValidation](https://www.adaptabletools.com/docs/reference/expressionoptions.md#performexpressionvalidation) | `boolean` | Validate Expressions before they can be run or saved | true | ---- ## Expression API [`Expression API`](https://www.adaptabletools.com/docs/reference/expressionapi.md) section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) contains functions which enable run-time access of AdapTableQL. | Method | Returns | Description | | --- | --- | --- | | [getAdaptableQueryExpression(query)](https://www.adaptabletools.com/docs/reference/expressionapi.md#getadaptablequeryexpression) | `string \| undefined` | Returns Expression string of given AdaptableQuery: can be Boolean, AggregatedBoolean, Scalar, AggregatedScalar or Observable | | [getAdaptableQueryExpressionWithColumnFriendlyNames(query)](https://www.adaptabletools.com/docs/reference/expressionapi.md#getadaptablequeryexpressionwithcolumnfriendlynames) | `string \| undefined` | Returns Expression string of given AdaptableQuery with column friendly names (instead of Column IDs) | | [getASTForExpression(expression)](https://www.adaptabletools.com/docs/reference/expressionapi.md#getastforexpression) | `any` | Runs the AST that AdapTableQL creates for an Expression - useful when evaluating remotely | | [getColumnsFromExpression(expression)](https://www.adaptabletools.com/docs/reference/expressionapi.md#getcolumnsfromexpression) | `string[]` | Returns all Columns referenced in an Expression | | [isColumnQueryable(abColumn)](https://www.adaptabletools.com/docs/reference/expressionapi.md#iscolumnqueryable) | `boolean` | Returns whether a Column is Queryable | | [isValidAggregatedBooleanExpression(expression, module, validationErrorMessage)](https://www.adaptabletools.com/docs/reference/expressionapi.md#isvalidaggregatedbooleanexpression) | `boolean` | Whether the given AggregatedBooleanExpression is valid | | [isValidAggregatedScalarExpression(expression, module, validationErrorMessage)](https://www.adaptabletools.com/docs/reference/expressionapi.md#isvalidaggregatedscalarexpression) | `boolean` | Whether the given AggregatedScalarExpression is valid | | [isValidBooleanExpression(expression, module, validationErrorMessage)](https://www.adaptabletools.com/docs/reference/expressionapi.md#isvalidbooleanexpression) | `boolean` | Whether the given BooleanExpression is valid | | [isValidObservableExpression(expression, module, validationErrorMessage)](https://www.adaptabletools.com/docs/reference/expressionapi.md#isvalidobservableexpression) | `boolean` | Whether the given ObservableExpression is valid | | [useCaseSensitivity()](https://www.adaptabletools.com/docs/reference/expressionapi.md#usecasesensitivity) | `boolean` | Whether Expressions are evaluated using Case Sensitivity | --- # Expression Types Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-types - There are 5 types of Expressions available in Adaptable: - `Standard` - When AdapTable needs to derive a scalar or boolean value from a single row - `Aggregated` - When AdapTable needs to derive a scalar or boolean value from a set of rows - `Observable` - A Reactive Expression used to watch data changes over time - `Cumulative` - Performs Cumulative Aggregations - `Quantile` - Creates 'buckets' of values There are 5 different types of Expressions provided by AdapTableQL. Each are available in different Modules as follows: | Type | Returns | Modules | | ----------------------------------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [Standard](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) | Single value of any type | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) (Boolean)

[Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) (Any)

[Export](https://www.adaptabletools.com/docs/handbook-exporting/index.md) (Boolean)

[Flashing Cell](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) (Boolean)

[Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) (Boolean)

[Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) (Boolean)

[Plus Minus](https://www.adaptabletools.com/docs/handbook-editing-plus-minus/index.md) (Boolean) | | [Observable](https://www.adaptabletools.com/docs/adaptable-ql-expression-observable/index.md) | Details of Row or Grid Changes | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) | | [Aggregation](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) | Single value (calculated across aggregated cells) | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) (Boolean)

[Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) (Any) | | [Cumulative](https://www.adaptabletools.com/docs/adaptable-ql-expression-cumulative/index.md) | Value from a Cumulative Calculation | [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) | | [Quantile](https://www.adaptabletools.com/docs/adaptable-ql-expression-quantile/index.md) | 'Buckets' of values | [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) | --- # Expression UI Components Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-expression-ui - AdapTable provides 2 UI Components to help write Expressions: - Expression Editor - ideal for complex queries with full drag and drop - Query Builder - used for more simple multi-column conditions using selects / dropdowns [Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) are widely used in AdapTable, including Alerts, Calculated Columns and Format Columns. An AdapTableQL Expression is ultimately just a human-readable string and can, therefore, be written by hand. Expressions provided in [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) might often be hand-produced AdapTable provides 2 different User Interface components available for writing Expressions. Use the `availableFilterEditors` property in [Grid Filter Options](https://www.adaptabletools.com/docs/handbook-grid-filter-technical-reference/index.md) to set which of the UI Components is available
--- # /docs/adaptable-ql-overview Canonical page: https://www.adaptabletools.com/docs/adaptable-ql-overview --- # Evaluating Expressions & Predicates Externally Canonical page: https://www.adaptabletools.com/docs/adaptable-server-evaluation - By default, Expressions and Predicates are evaluated automatically by AdapTable on the Client - However sometimes you might wish to peform the evaluation yourself on the server - AdapTable facilitates this for you by: - allowing you to choose which Modules (or Expressions) will evaluate on the Server or Client - firing Events to give you oversight of what needs evaluation - providing you with the AST that is used by AdapTableQL when managing Expressions Expression and Predicate evaluation by AdapTable is generally abstracted away. End users create Predicates and Expressions at run-time - either in the UI using [Wizards](https://www.adaptabletools.com/docs/ui-settings-panel-wizards/index.md) or the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) - or provide them at design-time in [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md), and everything "just works". But some developers have a more complicated 2-step use case: 1. run-time users will build Predicates and Expressions 2. but the developer team will perform the actual evaluation themselves on their Server This should not be confused with using the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) which forces server evaluation This page provides some tips and tricks to help achieve this. ## Specifying Externally Evaluated Modules The first, key, step is to tell AdapTable which [Modules](https://www.adaptabletools.com/docs/technical-reference-adaptable-modules/index.md) (or Expressions) should be evaluated externally. Four Modules can be evaluated externally: [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md), [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md), [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) and [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) This is done via the `evaluateAdaptableQLExternally` property in [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md). - This allows you to control when Server evaluation will take place - e.g. you can evaluate the Grid Filter remotely but let AdapTable manage Calculated Columns and Column Filters It is in the form of a function which receives context about the [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) / [Module](https://www.adaptabletools.com/docs/technical-reference-adaptable-modules/index.md) and returns a boolean. - This is only required when using AG Grid's **Client-Side Row Model** - If using the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) then **all** filtering (and sorting) is automatically ignored on the client ### `evaluateAdaptableQLExternally` Whether a Module (or a specific Expression / Predicate) should be evaluated externally By default AdapTable will perform all evaluations of Predicates and Expressions However you might prefer to evaluate a particular Module (e.g. Column Filters) externally (i.e. yourselves). Use this property to tell AdapTable which Modules (or Expressions) should not be evaluated by AdapTable. It is in the form of a function which receives context about the expression / module and returns a boolean. The context is of type [`EvaluateExpressionExternallyContext`](https://www.adaptabletools.com/docs/reference/evaluateexpressionexternallycontext.md) and is defined as follows: | Property | Type | Description | | --- | --- | --- | | [expression](https://www.adaptabletools.com/docs/reference/evaluateexpressionexternallycontext.md#expression) | `string` | Expression to evaluate | | [module](https://www.adaptabletools.com/docs/reference/evaluateexpressionexternallycontext.md#module) | [`AdaptableQLModule`](https://www.adaptabletools.com/docs/reference/adaptableqlmodule.md) | Module being evaluated: Alert, CalculatedColumn, ColumnFilter, GridFilter | | [object](https://www.adaptabletools.com/docs/reference/evaluateexpressionexternallycontext.md#object) | [`AdaptableObject`](https://www.adaptabletools.com/docs/reference/adaptableobject.md) | AdapTable Object which contains the Expression or Predicates | | [predicates](https://www.adaptabletools.com/docs/reference/evaluateexpressionexternallycontext.md#predicates) | [`AdaptablePredicate`](https://www.adaptabletools.com/docs/reference/adaptablepredicate.md)`[]` | Any Predicates to evaluate | | [referencedColumns](https://www.adaptabletools.com/docs/reference/evaluateexpressionexternallycontext.md#referencedcolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Columns contained in Expression | | [adaptableContext](https://www.adaptabletools.com/docs/reference/evaluateexpressionexternallycontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | The `module` property is of type [`AdaptableQLModule`](https://www.adaptabletools.com/docs/reference/adaptableqlmodule.md) which can be of one of 4 values: - `Alert` - runs [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) externally - `CalculatedColumn` - returns default value for the [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) so value can be provided externally - `ColumnFilter` - evaluates [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) externally - `GridFilter` - evaluates the [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) externally Leave this property undefined to maintain the default behaviour of AdapTableQL handling all evaluations ```ts {4,5} // Evaluate Columns Filters, Alerts & Calculated Columns in AdapTableQL // But evaluate the Grid Filter externally expressionOptions = { evaluateAdaptableQLExternally: (context: EvaluateExpressionExternallyContext) => { return context.module === 'GridFilter'; }, }, ``` In more advanced use cases you can use the Context object to make a per-instance decision as it contains: - the actual [Adaptable Object](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects) being evaluated - an `expression` property containing the [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) being evaluated - a `predicates` property containing the [Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) being evaluated ```ts {3} // Evaluate Expressions on the Server which use the MY_EXTERNAL_FUNCTION expression function expressionOptions = { evaluateAdaptableQLExternally: (context: EvaluateExpressionExternallyContext) => { return context.expression.includes('MY_EXTERNAL_FUNCTION') }, }, ``` ## Turning off Automatic Validation By default, AdapTableQL will validate Expressions automatically as they are being written. If you are evaluating the [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) on your server you might wish to set `performExpressionValidation` in [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md) to _false_ to avoid false positives. ### `performExpressionValidation` Validate Expressions before they can be run or saved By default AdaptablQL will validate all Expressions in the AdaptableUI before they can be run or saved. This is generally the preferred behaviour to avoid confusion. However sometimes, particularly if evaluation Expressions remotely, this can be intrusive and not helpful. Simply set the property to false and AdapTable will permit Expressions it cannot understand to run regardless: ```ts {4} // Don't allow AdapTableQL to validate Expressions expressionOptions = { expressionOptions: { performExpressionValidation: false, }, }; ``` ## Reducing Expression Complexity Expressions are very rich and powerful, and potentially extremely complex. When running on the Client that complexity is not problematic as AdapTable takes care of all evaluations. However if evaluating the Grid Filter (or Calculated Columns) on the server it means a lot of work is required. AdapTable helps you by allowing you to reduce the compexity of the Expressions in 2 ways: - Limiting which **functions** are available in Expressions - Limiting which **columns** can be included in Expressions or can be filtered - See [Reducing Expression Complexity](https://www.adaptabletools.com/docs/adaptable-ql-expression-managing/index.md) for more information - Consult [Managing System Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-system/index.md#managing-system-predicates) for instructions on limiting which **predicates** are available in Column Filters ## AdapTable Events As noted above, AdapTable will not evaluate any Modules for which the `evaluateAdaptableQLExternally` function returns *false*. Instead developers should subscribe to [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md) designed for this purpose. This allows developers to perform their own external evaluation as required The results of the external evaluation will then need to be returned to AdapTable and displayed accordingly. - There are many methods in [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md) which can be used to supply data to AdapTable - The most commmonly used is `setGridData` (see [Managing Grid Data](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md) for more information) AdapTable will automatically populate AG Grid with any data with which it is provided. It will also take care or re-applying all column sorts and column formats as required. The 3 most relevant [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md) are: ### Grid Filter Applied The [Grid Filter Applied Event](https://www.adaptabletools.com/docs/handbook-grid-filter-technical-reference/index.md) is published any time a [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) runs in AdapTable. It contains details of the Grid Filter's Expression and the AST used by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) to evaluate it. ### Column Filter Applied The [Column Filter Applied Event](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) is published each time Column Filters are applied. - If evaluating Column Filters externally, you can run them all in one batch if preferred - To do this set `manuallyApplyColumnFilter` in [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) to *true* (see [Manually Applying Column Filter](https://www.adaptabletools.com/docs/handbook-column-filter-manually-applying/index.md)) ### Calculated Column Changed 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. ### Using the AST AdapTable will make the AST it uses when evaulating an Expression available where necessary. - This is available in the `Info` property provided by the [Grid Filter Applied](https://www.adaptabletools.com/docs/handbook-grid-filter-technical-reference/index.md) and [Calculated Column Changed](https://www.adaptabletools.com/docs/handbook-calculated-column-technical-reference/index.md) Events: - `gridFilterExpressionAST` property in [`GridFilterAppliedInfo`](https://www.adaptabletools.com/docs/reference/gridfilterappliedinfo.md) - `calculatedColumnExpressionAST` property in [`CalculatedColumnChangedInfo`](https://www.adaptabletools.com/docs/reference/calculatedcolumnchangedinfo.md) Any Expression's AST can be retrieved via the `getASTForExpression` function in the [Expression API](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md) **Example: AdaptableQL Server Evaluation** Evaluating AdaptableQL on the Server - This example demonstrates Server Evaluation using Filters - In the demo we listen to the [Column Filter Applied Event](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) to get the latest applied Filters in the Grid - We then call our mock Server which translates the Predicate into SQL - the rough and ready code we used is [here](https://github.com/AdaptableTools/showcase-server-side-row-model/blob/master/server/SqlService.ts) - which runs the associated SQL Query - The server then returns the new data to AdapTable, which in turn populates AG Grid with it (using [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md) methods) ### Expand to see how Filters are evaluated externally We tell AdaptableQL not to evaluate Column Filters: ```ts expressionOptions: { evaluateAdaptableQLExternally: ( context: EvaluateExpressionExternallyContext ) => { return context.module === 'ColumnFilter' }, }, ``` In the AdaptableReady Event we populate the Grid with initial data: ```ts export const onAdaptableReady = async (info: AdaptableReadyInfo) => { const adaptableApi: AdaptableApi = info.adaptableApi; const gridOptions = info.gridOptions; const startRow = 0; const endRow = 1000; const response = await fetch(API_BASE, { method: 'post', body: JSON.stringify({ startRow, endRow, }), headers: {'Content-Type': 'application/json; charset=utf-8'}, }); const {rows} = await response.json(); adaptableApi.gridApi.loadGridData(rows); }; ``` And we listen to the Filter Applied Event to run the Filters externally and then repopulate the Grid with the results ```ts adaptableApi.eventApi.on( 'ColumnFilterApplied', async (eventInfo: ColumnFilterAppliedInfo) => { const filters = adaptableApi.filterApi.columnFilterApi.getColumnFilterDefs(); const request = { adaptableFilters: filters, includeSQL: true, startRow, endRow, }; gridOptions.api?.showLoadingOverlay(); const response = await fetch(API_BASE, { method: 'post', body: JSON.stringify(request), headers: {'Content-Type': 'application/json; charset=utf-8'}, }); const {rows, sql} = await response.json(); adaptableApi.gridApi.loadGridData(rows); gridOptions.api?.hideOverlay(); } ); ``` - Run a Column Filter in the Filter Bar and see how the Grid updates - Note how we output the SQL to [System Status Toolbar](https://www.adaptabletools.com/docs/handbook-system-status-message/index.md) ```ts import { AdaptableOptions, EvaluateExpressionExternallyContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'AdaptableQL Server Evaluation', expressionOptions: { evaluateAdaptableQLExternally: ( context: EvaluateExpressionExternallyContext ) => { return context.module === 'ColumnFilter'; }, }, initialState: { Dashboard: { Tabs: [ { Name: 'Main', Toolbars: ['SystemStatus', 'Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'athlete', 'gold', 'silver', 'bronze', 'totalMedals', '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 { AdaptableApi, ColumnFilterAppliedInfo, AdaptableReadyInfo, } from '@adaptabletools/adaptable'; const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!; export const onAdaptableReady = async (info: AdaptableReadyInfo) => { const adaptableApi: AdaptableApi = info.adaptableApi; const agGridApi = info.agGridApi; const startRow = 0; const endRow = 1000; const response = await fetch(API_BASE, { method: 'post', body: JSON.stringify({ startRow, endRow, }), headers: {'Content-Type': 'application/json; charset=utf-8'}, }); const {rows} = await response.json(); adaptableApi.gridApi.loadGridData(rows); adaptableApi.eventApi.on( 'ColumnFilterApplied', async (eventInfo: ColumnFilterAppliedInfo) => { const filters = adaptableApi.filterApi.columnFilterApi.getColumnFilterDefs(); const request = { adaptableFilters: filters, includeSQL: true, startRow, endRow, }; agGridApi.showLoadingOverlay(); const response = await fetch(API_BASE, { method: 'post', body: JSON.stringify(request), headers: {'Content-Type': 'application/json; charset=utf-8'}, }); const {rows, sql} = await response.json(); adaptableApi.systemStatusApi.setInfoSystemStatus( `SQL: ${sql.slice(0, 40)}`, sql ); adaptableApi.gridApi.loadGridData(rows); agGridApi.hideOverlay(); } ); }; ``` ```ts import {GridOptions, themeBalham} from 'ag-grid-enterprise'; import {WebFramework} from 'rowData'; import {columnDefs} from './columnDefs'; export const gridOptions: GridOptions = { theme: themeBalham, defaultColDef: { // headerName: '??', // colId: 'xxs', 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', 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, }, ]; ``` ## JSON Translation All Column Filter and Grid Filter objects (plus Alerts and Calculated Columns) in [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) are JSON. This means that in order to perform searching and filtering on the server this JSON will need to be 'translated' into something that the particular server can understand. Obviously each server is different so AdapTable cannot provide an out of the box implemenation, but we do work with a number of partners who have performed this for clients. We also have a [Grid Gurus consultancy service](https://www.adaptabletools.com/#grid-gurus) who can advise you in a bespoke manner. --- # Installing AdapTable Angular Canonical page: https://www.adaptabletools.com/docs/angular-installation - AdapTable Angular is installed from a public npm Registry ## Public npm Registry This page describes how to install AdapTable Angular 18 from the [public npm Registry](https://www.npmjs.com/package/@adaptabletools/adaptable-angular-aggrid). - Read [these instructions](https://www.adaptabletools.com/docs/getting-started-installation/index.md) for installing the "vanilla" (Framework-agnostic) version of AdapTable - See [Previous Documentation Versions](https://www.adaptabletools.com/docs/documentation-previous-versions/index.md) for instructions on installing older versions of AdapTable Angular ### Installing AdapTable Angular To install AdapTable Angular follow these steps: Use the `npm install` commmand npm install @adaptabletools/adaptable-angular-aggrid There is **no** need to install the AdapTable vanilla package For example to use Master-Detail functionality add: npm i @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 The currently required Angular peer dependencies are: - `@angular/common` >= 18.0.0 - `@angular/core` >= 18.0.0 npm i @angular/common npm i @angular/core The Minimum Version of Angular supported by AdapTable is 18 Install the AG Grid Angular and Enterprise packages (version 35.2 or later) npm install ag-grid-angular 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: '', }; ``` ## CJS AdapTable Angular is packaged using the standard [Angular package format](https://angular.dev/tools/libraries/angular-package-format). Since [Angular v13](https://github.com/angular/angular/issues/44096#issuecomment-962436958) this is **not available in CJS format**. This means that unlike AdapTable's Vanilla, React and Vue versions, AdapTable Angular is **only** available in ESM. - You might need the CJS format or to use third party libraries that require the CJS format (e.g. **Jest**) - In this use case, you will need to use some additional build tools/libraries to overcome this Angular limitation ## CommonJS Build Warnings When building an Angular application which uses AdapTable, you may see warnings like: ``` [WARNING] Module 'react' used by 'node_modules/@adaptabletools/adaptable/...' is not ESM CommonJS or AMD dependencies can cause optimization bailouts. ``` These warnings are emitted by all Angular builders — both the esbuild-based ones (`@angular/build:application`, `@angular-devkit/build-angular:browser-esbuild`) and the older webpack-based one (`@angular-devkit/build-angular:browser`, where the message reads `'...' depends on 'react'` instead). These warnings refer to React ecosystem packages used internally by AdapTable (`react`, `react-dom`, and the transitive dependency `use-sync-external-store`). These packages are published as CommonJS only — no ESM distribution exists — so the warnings cannot be avoided at the package level. The warnings are harmless: the build output is correct, and the "optimization bailout" only means the bundler cannot tree-shake inside those specific modules (which would have no effect on React's monolithic runtime anyway) To silence the warnings, add the packages to the [allowedCommonJsDependencies](https://angular.dev/tools/cli/build#configuring-commonjs-dependencies) build option — in `angular.json`, or in `project.json` if you are using an Nx monorepo: ```json { "targets": { "build": { "executor": "@angular/build:application", "options": { "allowedCommonJsDependencies": [ "react", "react-dom", "use-sync-external-store" ] } } } } ``` Listing a package name also covers its deep imports (e.g. `react/jsx-runtime`, `react-dom/client`, `use-sync-external-store/shim`), so these three entries are sufficient --- # Integrating AdapTable Angular Canonical page: https://www.adaptabletools.com/docs/angular-integration - To use AdapTable Angular, you need to: - Import `AdaptableAngularAgGridModule` into your application - Provide and configure 3 components: ``, `` and `` Creating applications that use AdapTable Angular 20 is straightforward. - See [Previous Documentation Versions](https://www.adaptabletools.com/docs/documentation-previous-versions/index.md) for instructions on integrating older versions of AdapTable Angular ## Defining the Key Components There are 3 key Angular components that need to be provided: - **``**: manages [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) and orchestrates the AdapTable and AG Grid components - **``**: renders AdapTable's UI including the [Dashboard](https://www.adaptabletools.com/docs/ui-dashboard/index.md) - **``**: standard AG Grid Angular component with the `*adaptable` structural directive applied ### Defining the 3 Angular Components Import 2 modules into your application: - `AdaptableAngularAgGridModule` from Adaptable Tools - `AgGridModule` from AG Grid ```ts import { AdaptableAngularAgGridModule } from '@adaptabletools/adaptable-angular-aggrid'; import {AgGridModule} from 'ag-grid-angular'; @NgModule({ imports: [ AgGridModule, AdaptableAngularAgGridModule, // ... ], // ... }) export class AppModule {} ``` Import the [AG Grid Enterprise Modules](https://www.adaptabletools.com/docs/getting-started-aggrid-modules/index.md). Place this in an array - which will later be passed to the component. ```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 agGridModules: 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). Place in an array - which will later be passed to the component. ```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 agGridModules: 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) Place in an array - which will later be passed to the component. ```jsx // Import AG Grid Modules import { Module, ClientSideRowModelModule, CsvExportModule, ExcelExportModule, MasterDetailModule } from 'ag-grid-enterprise'; // Create Modules array (passed later to Adaptable Initializer) export const agGridModules: 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 (including correct [cell data types](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md)) - initial data (if not lazy loading) - AG Grid events - additional, required properties ```js 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, }; ``` - **All GridOptions properties** should be included in the `gridOptions` Input (not as direct Inputs on the `` component) - This approach ensures a consistent and streamlined interface for grid configuration in all scenarios (lazy loading, server-side data, etc.) - The [rowData](https://www.ag-grid.com/angular-data-grid/grid-options/#reference-clientRowModel-rowData) prop is the **only exception** and has flexibility to be passed as separate input to `` component - However, this is not mandatory, and it can also be included within the `gridOptions` Input, with the other props - Always set the appropriate `cellDataType` property in ColumnDefs for every Column, to enable [AdapTable to use the correct Filters and related properties](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) - 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) Import AdapTable Types from `@adaptabletools/adaptable-angular-aggrid` (e.g. `AdaptableApi`, `AdaptableOptions`, `InitialState` etc.) ```ts import { type AdaptableOptions, type AdaptableApi, type InitialState, type AdaptableColumn } from '@adaptabletools/adaptable-angular-aggrid'; ``` `index.css` contains core styles (and supports both `light` and `dark` themes) ```ts import "@adaptabletools/adaptable-angular-aggrid/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 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 `Pricing` - Created a [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) called Cars with 3 columns and Row Grouping for the *Make* column - Set a [Custom Sort](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md) for the 'Rating' Column so it will sort more intuitively for the users ```tsx const initialState: InitialState = { Dashboard: { PinnedToolbars: ['Layout', 'Pricing'], }, Layout: { CurrentLayout: 'Cars', Layouts: [ { TableColumns: [ 'Model', 'Price', 'Make'], RowGroupedColumns: ['Make'], Name: 'Cars', }, ], }, 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 [AdaptableId](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 you purchase 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 in Step 6 - any [Plugins](https://www.adaptabletools.com/docs/technical-reference-plugins/index.md) required (e.g. the No Code Plugin) - any of the other many properties and objects 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: false, }, }, initialState: initialState, plugins: [nocode()], stateOptions: { persistState: () => Promise.resolve(), // implement remote persistence loadState: () => Promise.resolve(null), // 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 Component"> Render the `` component in your application. Following input properties are **mandatory**: - `adaptableOptions` - provide the object created in step 7 - `gridOptions` - pass in GridOptions object created in step 3 - `modules` - pass in Modules object created in step 2 Optionally you can also subscribe to the [AdapTable Ready Event](https://www.adaptabletools.com/docs/getting-started-adaptable-ready/index.md) which is emitted when AdapTable has initialised (see Step 10). ```html {1,8} ``` Component"> Render the `` component inside ``. This component manages AdapTable's UI & [Dashboard](https://www.adaptabletools.com/docs/ui-dashboard/index.md) ```html {7} ``` Component"> Also render the `` component (AG Grid's Angular component) inside ``. This should include AdapTable's structural directive - `*adaptable` - which defines the AdapTable context. It should also include bindings to: - the `gridOptions` object defined in Step 3 - the `modules` objects defined in Step 2 ```html {8,10,12,14} *adaptable="let adaptable" [gridOptions]="adaptable.gridOptions" [modules]="adaptable.modules" style="flex: 1" > ``` - The `` component should get its `gridOptions` and `modules` Inputs from the Adaptable context - They should **not** be given directly from the parent component - Always use a single `gridOptions` Input for **all** grid related props, not as direct Inputs on the `` component - This ensures a consistent and streamlined grid configuration in all scenarios (lazy loading, server-side data, etc.) The [Adaptable Ready Event](https://www.adaptabletools.com/docs/getting-started-adaptable-ready/index.md) is fired when AdapTable is initialised, and should be used to perform any setup related actions required. The [`AdaptableReadyInfo`](https://www.adaptabletools.com/docs/reference/adaptablereadyinfo.md) object provided by the Event, contains 2 important 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 ```html {5,12} export class AppComponent { adaptableReady = ({ adaptableApi, agGridApi }: AdaptableReadyInfo) => { // use AdaptableApi for runtime access to AdapTable this.adaptableApi = adaptableApi; this.adaptableApi.quickSearchApi.runQuickSearch('toy'); // use AG Grid's Api for runtime access to AG Grid if needed this.agGridApi = agGridApi; this.agGridApi.autoSizeAllColumns(); }; } ``` - AG Grid's `gridReady` event should **not** be used - because it will fire **before** AdapTable has initialised - Instead, you should always use AdapTable's `adaptableReady` event See the [Integration](https://www.adaptabletools.com/docs/getting-started-integration/index.md) section in Getting Started for related articles 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) --- # AdapTable Angular Canonical page: https://www.adaptabletools.com/docs/angular-overview --- # AdapTable State Guide Canonical page: https://www.adaptabletools.com/docs/dev-guide-adaptable-state - AdapTable provides a powerful State-management architecture - AdapTable State comprises 2 sets of [Adaptable Objects](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects) and associated settings: - [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) provided by developers at design-time - changes to these objects (plus any new ones created) made by Users at run-time - AdapTable provides full State persistence and retrieval mechanisms of AdapTable State - AdapTable State does **not** include AG Grid data; it deals only with the AdapTable UI and associated objects - Likewise AdapTable does **not** have access to the clients' private data Managing User State is one of the most valued pieces of functionality that AdapTable provides. It allows developers to configure AdapTable with the objects their users needs. It also provides a mechanism whereby these objects - and any subsequent additions, modifications and deletions - are automatically persisted and fetched as required on subsequent application re-starts. ## Contents of AdapTable State User State comprises 2 elements: - state provided at **design-time** (using [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md)) for initial use - state created at **run-time** through user action (e.g. selecting a [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md), creating a [Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) etc.) See [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) for extensive information on pre-populating AdapTable instances with initial User State ## How AdapTable State Works AdapTable State can best be seen as a 3 stage process, as follows: At design-time developers will create [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md). This is a JSON object that contains the items the AdapTable instance requires for initial use. It consists of multiple sections - each relating to one Module in AdapTable. Some of the contents of each section are collections of Adaptable Objects (e.g. [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md)) but can also be string properties (e.g name of the Current Layout). When the application loads for the **first time**, the [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) is read into memory. This Initial State is then stored as AdapTable State and is updated (and automatically persisted) with any user state that is created during that session. It can be stored locally or remotely depending on your settings (see below for more information). Subsequently, each time the application is launched, that persisted User State is retrieved and the particular AdapTable instance is pre-populated with it This allows AdapTable users always to see the same state as was persisted on their previous visit. This allows AdapTable users always to see the same state as was persisted on their previous visit. ### Initial Adaptable State Initial State is provided by developers to populate each new AdapTable instance for first use. - As the name indicates, Initial Adaptable State is intended **only for first-time** use of the Application - AdapTable State should be relied on to manage all subsequent state-related behaviour This means that when end-users open the new application for the first time, they won't just see a clean AG Grid instance but, rather, one pre-loaded with multiple Searches, Styles, Edit Rules, Reports etc. The Initial Adaptable State is then automatically saved into AdapTable State which is subsequently used during the Application's lifetime. The useful [Revision](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#revision-property) property allows developers to update Initial State **after** it has been initially loaded See [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) for a full Guide to this topic ### Redux Internally AdapTable uses [Redux](https://redux.js.org/) to manage its state. This provides a uni-directional store for all the objects used in the grid If using Redux in your application, continue to maintain your own Store; merging the 2 Stores can cause complications ## Persisting AdapTable State AdapTable State is designed to be persisted allowing for a seamless user experience between sessions. AdapTable State can be saved in 2 different ways: - Local Storage - by default, AdapTable State is stored in the browser's local storage - Remote Storage - accessible via a series of JavaScript functions available in State Options See [Persisting AdapTable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence/index.md) for detailed discussion about how to save state ## Default AdapTable State AdapTable State is, by design, almost entirely empty when the Application starts for the first time. It is then populated by the supplied [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md). However there are 4 default properties which AdapTable provides for convenience sake: All of these can be replaced by properties in Initial Adaptable State if necessary | Module | Default Property Description | | ---------------------------------------------------------------- | -------------------------------------------------------------------- | | [Dashboard](https://www.adaptabletools.com/docs/ui-dashboard/index.md) | A *SettingsPanel* Button is provided in the `ModuleButtons` property | | [Quick Search](https://www.adaptabletools.com/docs/handbook-quick-search/index.md) | Quick Search Highlight Style (Black Text on Yellow Background) | | [Theme](https://www.adaptabletools.com/docs/handbook-theming/index.md) | Current Theme is set to "light" | | [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) | A *SettingsPanel* Button is provided in the `ModuleButtons` property | ## Monitoring AdapTable State The [Adaptable State Changed Event](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-events/index.md) allows developers and support to monitor all changes in the State. It is fired every time that any Adaptable State changes. ## Migrating AdapTable State AdapTable will make changes to Adaptable State from time to time as requirements change. Most of these changes are purely additive - typically the result of user enhancements requests. However once a year AdapTable might introduce breaking changes to Adaptable State. When this happens, AdapTable will migrate the State automatically, although developers can opt out from this and perform all State updates manually. Learn more about [Migrating AdapTable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-migrating-state/index.md) and the different options available --- # Adaptable State Changed Event Canonical page: https://www.adaptabletools.com/docs/dev-guide-adaptable-state-changed-event Please see [Adaptable State Events](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-events/index.md) for full details --- # Custom AdapTable State Canonical page: https://www.adaptabletools.com/docs/dev-guide-adaptable-state-custom - Bespoke data can be stored in AdapTable State by using the Application section AdapTable provides the Application section of [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) for storing custom state. Another, perhaps better, way of storing custom state is to use the `saveState` function (see below) Application contains a simple set of key / value pairs designed for storing bespoke data. A common use case is to store grid-related options which the User changed (e.g. Filter Bar visibility). AdapTable takes care of the full persistence / retrieval of these objects as part of [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) **Example: Custom Data in Adaptable State** Using Application Initial State to save bespoke user data - This example shows how you can use Application section of Adaptable State to store custom data - using Supabase to persist data between sessions - 2 properties are kept in Application State: - the time when the button was clicked - whether Filter bar is displayed - When the demo first loads the Grid shows with the Filter Bar hidden (as visibility was set to false in Filter Options) and with the Button showing loaded time - Each time Filter Bar Visibility is changed - either through Toolbar or via the Column Menu - an entry in Application State is updated - Likewise each time the Button is clicked the Application State is updated and the Button displays the time it was updated - Refreshing the grid will display the Grid with Filter bar as it was last set and the button showing the last time it was clicked ```ts stateOptions: { loadState: (config: AdaptableStateFunctionConfig) => { return supabaseService.loadAdaptableState(config.adaptableStateKey); }, persistState: ( state: Partial, config: AdaptableStateFunctionConfig ) => { return supabaseService.persistAdaptableState( state, config.adaptableStateKey, config.userName ); } } ``` - Refresh the page and note that the Filter Bar visibility is the same value to which it was last set and the Button time is not updated - Reset the persisted state and note that now the Filter Bar is hidden (as value from Filter Options is used) and the Button click count is reset ```ts import { AdaptableApi, AdaptableButton, AdaptableOptions, AdaptableState, AdaptableStateFunctionConfig, ApplicationDataEntry, CustomToolbarButtonContext, DashboardButtonContext, } from '@adaptabletools/adaptable'; import {SupabasePersistenceService} from './SupabasePersistenceService'; import {WebFramework} from 'rowData'; const supabaseService = new SupabasePersistenceService(); export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Application State Demo', adaptableStateKey: 'docs/ApplicationStateDemo', filterOptions: { columnFilterOptions: { showQuickFilter: false, }, }, dashboardOptions: { customDashboardButtons: [ { label: 'Reset State', buttonStyle: { tone: 'neutral', variant: 'outlined', }, onClick: ( _button: AdaptableButton, context: DashboardButtonContext ) => { supabaseService.clearAdaptableState( context.adaptableApi.optionsApi.getAdaptableStateKey(), context.userName ); context.adaptableApi.applicationApi.editApplicationDataEntry({ Key: 'TimesClicked', Value: 0, }); context.adaptableApi.stateApi.reloadInitialState(); }, }, ], customToolbars: [ { name: 'TimesClickedButton', toolbarButtons: [ { label: 'Click Me', buttonStyle: { tone: 'neutral', variant: 'outlined', }, onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { let entry: ApplicationDataEntry | undefined = context.adaptableApi.applicationApi.getApplicationDataEntryByKey( 'TimesClicked' ); if (entry) { entry.Value = entry.Value + 1; context.adaptableApi.applicationApi.editApplicationDataEntry( entry ); context.adaptableApi.systemStatusApi.setWarningSystemStatus( 'Times Clicked: ' + entry.Value ); } }, }, ], }, ], }, stateOptions: { loadState: (config: AdaptableStateFunctionConfig) => { return supabaseService.loadAdaptableState(config.adaptableStateKey); }, persistState: ( state: Partial, config: AdaptableStateFunctionConfig ) => { return supabaseService.persistAdaptableState( state, config.adaptableStateKey, config.userName ); }, }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['ColumnFilter', 'TimesClickedButton', 'SystemStatus'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', 'has_wiki', 'pushed_at', 'open_issues_count', ], AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import { AdaptableReadyInfo, ApplicationDataEntry, } from '@adaptabletools/adaptable'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { const timesClickedEntryKey: string = 'TimesClicked'; let timesClickedEntry: ApplicationDataEntry | undefined = adaptableApi.applicationApi.getApplicationDataEntryByKey( timesClickedEntryKey ); if (!timesClickedEntry) { timesClickedEntry = { Key: timesClickedEntryKey, Value: 0, }; adaptableApi.applicationApi.addApplicationDataEntry(timesClickedEntry); } if (timesClickedEntry.Value > 0) { adaptableApi.systemStatusApi.setSuccessSystemStatus( 'Times Clicked: ' + timesClickedEntry.Value ); } else { adaptableApi.systemStatusApi.setInfoSystemStatus( 'Times Clicked: ' + timesClickedEntry.Value ); } let filterVisibilityEntry: ApplicationDataEntry | undefined = adaptableApi.applicationApi.getApplicationDataEntryByKey( 'QuickFilterVisibility' ); if (filterVisibilityEntry) { filterVisibilityEntry.Value == true ? adaptableApi.filterApi.columnFilterApi.showQuickFilterBar() : adaptableApi.filterApi.columnFilterApi.hideQuickFilterBar(); } adaptableApi.eventApi.on('AdaptableStateChanged', stateChangedInfo => { if (stateChangedInfo.actionName == 'SYSTEM_QUICK_FILTER_BAR_SHOW') { filterVisibilityEntry = { Key: 'QuickFilterVisibility', Value: true, }; adaptableApi.applicationApi.editApplicationDataEntry( filterVisibilityEntry ); } if (stateChangedInfo.actionName == 'SYSTEM_QUICK_FILTER_BAR_HIDE') { filterVisibilityEntry = { Key: 'QuickFilterVisibility', Value: false, }; adaptableApi.applicationApi.editApplicationDataEntry( filterVisibilityEntry ); } }); }; ``` ```ts import {createClient, SupabaseClient} from '@supabase/supabase-js'; import {dbConfig} from './dbConfig'; /** * This is a simple implementation of the Adaptable Persistence Service that uses Supabase as the underlying storage mechanism. * * @see {@link https://supabase.com/} */ export class SupabasePersistenceService { private supabase: SupabaseClient; private stateTable = 'adaptable_state_docs'; private debugMode: boolean; constructor(config?: {debugMode: boolean}) { this.supabase = createClient( dbConfig.supabaseUrl, dbConfig.supabaseKey ); this.debugMode = !!config?.debugMode; } async loadAdaptableState(stateKey: string): Promise { const {data, error} = await this.supabase .from(this.stateTable) .select() .eq('state_key', stateKey); if (error) { this.log(`LOAD_STATE::${stateKey}`, 'ERROR'); console.error(error); return {}; } // @ts-ignore const stateTextValue = data?.[0]?.state_value ?? '{}'; this.log(`LOAD_STATE::${stateKey}`, data); return JSON.parse(stateTextValue); } async persistAdaptableState( state: any, stateKey: string, userName: string ): Promise { const stateTextValue = JSON.stringify(state); const {error} = await this.supabase.from(this.stateTable).upsert({ state_key: stateKey, state_value: stateTextValue, last_changed_by: userName, }); if (error) { this.log(`PERSIST_STATE::${stateKey}`, 'ERROR'); console.error(error); } else { this.log(`PERSIST_STATE::${stateKey}`, state); } } async clearAdaptableState(stateKey: string, userName: string): Promise { const {error} = await this.supabase.from(this.stateTable).upsert({ state_key: stateKey, state_value: '{}', change_counter: 0, last_changed_by: userName, }); if (error) { this.log(`CLEAR_STATE::${stateKey}`, 'ERROR'); console.error(error); } else { this.log(`CLEAR_STATE::${stateKey}`); } } async resetEntireAdaptableState(): Promise { // delete all rows in table const {error} = await this.supabase.from(this.stateTable).delete(); if (error) { console.error(error); } else { this.log(`RESET_STATE`); } } private log(...params: any) { if (!this.debugMode) { return; } console.log(...params); } } /** * Database Table Schema */ interface Database { public: { Tables: { adaptable_state_docs: { Row: { change_counter: number | null; created_at: string; last_changed_by: string | null; state_key: string; state_value: string | null; updated_at: string | null; }; Insert: { change_counter?: number | null; created_at?: string; last_changed_by?: string | null; state_key: string; state_value?: string | null; updated_at?: string | null; }; Update: { change_counter?: number | null; created_at?: string; last_changed_by?: string | null; state_key?: string; state_value?: string | null; updated_at?: string | null; }; Relationships: []; }; }; Views: { [_ in never]: never; }; Functions: { [_ in never]: never; }; Enums: { [_ in never]: never; }; CompositeTypes: { [_ in never]: never; }; }; } ``` ```ts export const dbConfig = { supabaseUrl: 'https://uqbssslumnnwqwcmdcoc.supabase.co', supabaseKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVxYnNzc2x1bW5ud3F3Y21kY29jIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDI1NTA4MzQsImV4cCI6MjAxODEyNjgzNH0.nyCiCwNhgQtY3TF3VmJlEI22YC8YpH0DlEC_cb9tamM', }; ``` ## Application State Config The Application section of Adaptable State contains a collection of `ApplicationDataEntries` objects: | Property | Type | Description | | --- | --- | --- | | [ApplicationDataEntries](https://www.adaptabletools.com/docs/reference/applicationstate.md#applicationdataentries) | [`ApplicationDataEntry`](https://www.adaptabletools.com/docs/reference/applicationdataentry.md)`[]` | Array of Key / Value pairs enabling custom data to be stored in Adaptable State. | ### ApplicationDataEntry Each ApplicationDataEntry is a simple key / value pair: | Property | Type | Description | | --- | --- | --- | | [Key](https://www.adaptabletools.com/docs/reference/applicationdataentry.md#key) | `string` | Key of Key / Value pair - always stored as a string | | [Value](https://www.adaptabletools.com/docs/reference/applicationdataentry.md#value) | `any` | Value of Key / Value pair (actual data being stored) - needs to stringifiable | ## Application API The Application API section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) contains functions for managing the Application section of AdapTable State: | Method | Returns | Description | | --- | --- | --- | | [addApplicationDataEntry(applicationDataEntry)](https://www.adaptabletools.com/docs/reference/applicationapi.md#addapplicationdataentry) | `void` | Adds new Application Data Entry | | [createApplicationDataEntry(key, value)](https://www.adaptabletools.com/docs/reference/applicationapi.md#createapplicationdataentry) | `void` | Creates new Application Data Entry with given Key and Value | | [deleteApplicationDataEntry(applicationDataEntry)](https://www.adaptabletools.com/docs/reference/applicationapi.md#deleteapplicationdataentry) | `void` | Deletes given Application Data Entry | | [editApplicationDataEntry(applicationDataEntry)](https://www.adaptabletools.com/docs/reference/applicationapi.md#editapplicationdataentry) | `void` | Edits given Application Data Entry | | [getApplicationDataEntries()](https://www.adaptabletools.com/docs/reference/applicationapi.md#getapplicationdataentries) | [`ApplicationDataEntry`](https://www.adaptabletools.com/docs/reference/applicationdataentry.md)`[]` | Retrieves all Key Value Pairs in Application state | | [getApplicationDataEntriesByValue(value)](https://www.adaptabletools.com/docs/reference/applicationapi.md#getapplicationdataentriesbyvalue) | [`ApplicationDataEntry`](https://www.adaptabletools.com/docs/reference/applicationdataentry.md)`[]` | Gets Application Data Entry with given value | | [getApplicationDataEntryByKey(key)](https://www.adaptabletools.com/docs/reference/applicationapi.md#getapplicationdataentrybykey) | [`ApplicationDataEntry`](https://www.adaptabletools.com/docs/reference/applicationdataentry.md)` \| undefined` | Gets Application Data Entry with given key | | [getApplicationState()](https://www.adaptabletools.com/docs/reference/applicationapi.md#getapplicationstate) | [`ApplicationState`](https://www.adaptabletools.com/docs/reference/applicationstate.md) | Retrieves Application section from Adaptable State | --- # Listening to AdapTable State Canonical page: https://www.adaptabletools.com/docs/dev-guide-adaptable-state-events - The AdapTable State Changed Event fires whenever anything changes in Adaptable State - This provides a comprehensive overview of all activity in AdapTable and AG Grid - The AdapTable State Reloaded Event fires when State reloads for whatever reason AdapTable provides a comprehensive overview of all AdapTable state changes. This means all grid activity - every action, layout change, mouse click etc. - can be listened to as required. The Event's messages can easily be streamed to 3rd party monitoring applications for use by Support Teams This is achieved using the Adaptable State Changed Event which provides a stream of all state changes. There is also an Adaptable State Reloaded Event which fires when the State is reloaded ## AdapTable State Changed Event The Adaptable State Changed Event is fired every time that any [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) changes. The [Event's Info](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-technical-reference/index.md) provides very extensive information about the State Change in question including: - what action triggered the change - who was the user - when it happend - which AdapTable instance - before and after copies of Adaptable State **Example: Adaptable State Changes** Monitoring changes in AdapTable State - In this example we listen to the Adaptable State Changed Event and output each Message: - In full to the console - As a [System Status Message](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md) with the Action Name as the `Header` and the full message as the `Description` - Perform some typical activity in the Grid and open System Status screen to see the full details of all the messages sent ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Adaptable State Changed', initialState: { Dashboard: { Tabs: [ { Name: 'Default', Toolbars: ['SystemStatus'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['SystemStatus'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', 'has_wiki', 'pushed_at', 'open_issues_count', ], AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import { AdaptableReadyInfo, AdaptableStateChangedInfo, } from '@adaptabletools/adaptable'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { adaptableApi.eventApi.on( 'AdaptableStateChanged', (stateChangedInfo: AdaptableStateChangedInfo) => { // ignore system status events // calling `setInfoSystemStatus` triggers another event if (!stateChangedInfo.action.type.includes('SYSTEM_STATUS')) { let info = ''; try { // it fails for objects with complex references info = JSON.stringify(stateChangedInfo.action); } catch (e) { info = 'Could not stringify action'; } const message = 'Action Name: ' + stateChangedInfo.actionName; adaptableApi.systemStatusApi.setInfoSystemStatus(message, info); console.info('Audit Message', { actionName: stateChangedInfo.actionName, // logging string version // the SandPack gets slow when logging complex objects info, }); } } ); }; ``` ### Filtering State Changed Messages The Event's Args can be filtered so only particular actions are logged. This allows Support Teams to listen only to the grid changes that they are interested in **Example: Filtering Adaptable State Changed Messages** Filtering messages fired by the Adaptable State Changed Event - In this example we filter the Adaptable State Changed Event only to log messages relating to Quick Search, Column Filters and the Grid Filter. - We send the messages provided by the Event: - In full to the console - As a [System Status Message](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md) with the Action Name as the `Header` and the full message as the `Description` - Run some quick searches and see the Event messages that are sent - Perform other Grid actions and note that nothing is sent processed by the Event ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Filtering Adaptable State Changed', initialState: { Dashboard: { PinnedToolbars: ['SystemStatus', 'GridFilter'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['SystemStatus', 'QuickSearch'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', 'has_wiki', 'pushed_at', 'open_issues_count', ], AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; import {AdaptableStateChangedInfo} from '@adaptabletools/adaptable'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { adaptableApi.eventApi.on( 'AdaptableStateChanged', (stateChangedInfo: AdaptableStateChangedInfo) => { // ignore system status events // calling `setInfoSystemStatus` triggers another event if ( stateChangedInfo.action.type.includes('QUICK_SEARCH') || stateChangedInfo.action.type.includes('GRID_FILTER') || stateChangedInfo.action.type.includes('COLUMN_FILTER') ) { let info: any = stateChangedInfo.action; try { // it fails for objects with complex references info = JSON.stringify(stateChangedInfo.action); } catch (e) { info = 'Could not stringify action'; } const message = 'Action Name: ' + stateChangedInfo.actionName; adaptableApi.systemStatusApi.setInfoSystemStatus( message, 'text: ' + info ); console.info('Audit Message', { actionName: stateChangedInfo.actionName, // logging string version // the SandPack gets slow when logging complex objects info, }); } } ); }; ``` ### Actions Each State Change is triggered by a [Redux Action](https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers) (the technical solution Adaptable uses to manage state) Each Action contains useful objects pertaining to that particular change. For instance the `GRID_DATA_CHANGED` and `GRID_DATA_EDITED` actions both contain a [`CellDataChangedInfo`](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md) object that provides full details of the the column, row, and new and old values. #### Action Names To help Support Teams, the `actionName` property in the Action is also provided as a full level property. It describes exactly what the Action does, and can be used to listen to a particular State Change. For instance to react to values being changed a [FreeText Column](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) you would do: ```ts api.eventApi.on( 'AdaptableStateChanged', (statechangedInfo: AdaptableStateChangedInfo) => { if ( statechangedInfo.actionName == 'FREE_TEXT_COLUMN_ADD_EDIT_STORED_VALUE' ) { // do something with the change } } ); ``` ### Full Action Name List This is the full list of all `actionName` properties, together with what the Action does: @import file="reduxactions/reduxactions.page.md" section="Redux Actions" ## Other State Events AdapTable provides 2 other Events that handle changes in AdapTable State: ### Before AdapTable State Changes The `BeforeAdaptableStateChanges` Event fires **before** a change is made in AdapTable State. - This is very useful if you wish to show a progress indicator for an action which takes several seconds - Or if there are other actions which you wish to perform while the State changes The `EventInfo` contains the current State and the Redux Action which is about to be performed. - It is not possible to cancel the Redux Action with this Event - Do **not** use this event to mutate the Adaptable state (e.g. to dispatch another action) ### AdapTable State Reloaded The `AdaptableStateReloaded` Event fires whenever the AdapTable State reloads. The `EventInfo` contains the new and old state allowing users easily to diff the changes. --- # Providing Initial Adaptable State Canonical page: https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state - AdapTable instances are pre-populated at Design Time with Initial Adaptable State - These are the objects that Users require for first time use - When Adaptable loads, the Initial State is saved into [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) - The contents of this Initial State is arranged by Module and consist of both: - individual properties - collections of AdapTable Objects See the list of Initial State sections in [Initial Adaptable State Reference](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md) Developers will populate each new AdapTable instance with **initial Adaptable State**. This means that when end-users open the new application for the first time, they won't just seen a clean AG Grid instance but, rather, one pre-loaded with multiple Layouts, Searches, Styles, Edit Rules, Reports etc. - Initial State constitutes those objects which can (and will) be **overridden** at run-time and saved by user's actions - Anything which **cannot** be changed at run-time is provided through [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) This enables a grid to be provided that matches users needs, allowing them to be productive immediately. The Initial State is then merged into [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-management/index.md) and can be added or edited (if the user's [Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) allow) and persisted (either locally or remotely) using AdapTable's State Management. - As the name implies Initial State should **only** be used for **first-time** use of the Application - AdapTable State should be relied on to manage all subsequent state-related behaviour - We try hard to ensure that all changes to the `InitialState` object are fully backwardly compatible - Where this is not possible we provide [Automatic Adaptable State Migration](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-migrating-state/index.md) to ease the transition ## The Basics Initial State is a JSON object created at design-time. It consists of a series of (nullable) properties that themselves each implement the [`BaseState`](https://www.adaptabletools.com/docs/reference/basestate.md) class. Most of the contents of each section are collections of Adaptable Objects (e.g. [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md)) but can also be string properties (e.g name of the Current Layout). It is provided to AdapTable via the `initialState` property in the base section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md). ### `initialState` Initial Adaptable Objects provided in an Adaptable Instance [`InitialState`](https://www.adaptabletools.com/docs/reference/initialstate.md) Inital State is the Adaptable State provided at design time for **first-time** use. The full definition of the object is as follows: | Property | Type | Description | | --- | --- | --- | | [Alert](https://www.adaptabletools.com/docs/reference/initialstate.md#alert) | [`AlertState`](https://www.adaptabletools.com/docs/reference/alertstate.md) | Collection of `AlertDefinitions` which will fire Alerts when the rule is met | | [Application](https://www.adaptabletools.com/docs/reference/initialstate.md#application) | [`ApplicationState`](https://www.adaptabletools.com/docs/reference/applicationstate.md) | Empty state section (only populated at Design Time) available for User to store their own data with the rest of AdapTable state. | | [CalculatedColumn](https://www.adaptabletools.com/docs/reference/initialstate.md#calculatedcolumn) | [`CalculatedColumnState`](https://www.adaptabletools.com/docs/reference/calculatedcolumnstate.md) | Collection of *CalculatedColumn* objects that will display a value based on other cells in the row (using a Calculated Column Expression) | | [Charting](https://www.adaptabletools.com/docs/reference/initialstate.md#charting) | [`ChartingState`](https://www.adaptabletools.com/docs/reference/chartingstate.md) | Named Charts (wrapping Chart models) | | [CustomSort](https://www.adaptabletools.com/docs/reference/initialstate.md#customsort) | [`CustomSortState`](https://www.adaptabletools.com/docs/reference/customsortstate.md) | Collection of *Custom Sort* objects to allow some columns to be sorted in non-standard (e.g. non alphabetical) ways | | [Dashboard](https://www.adaptabletools.com/docs/reference/initialstate.md#dashboard) | [`DashboardState`](https://www.adaptabletools.com/docs/reference/dashboardstate.md) | Large series of properties to give users full control over the look and feel of the *Dashboard* - the section above the grid with toolbars and buttons | | [Export](https://www.adaptabletools.com/docs/reference/initialstate.md#export) | [`ExportState`](https://www.adaptabletools.com/docs/reference/exportstate.md) | Collection of *Report* objects, together with name of the Current Report, as part of AdapTable export Module | | [FlashingCell](https://www.adaptabletools.com/docs/reference/initialstate.md#flashingcell) | [`FlashingCellState`](https://www.adaptabletools.com/docs/reference/flashingcellstate.md) | Definitions of which cells flash in response to data changes | | [FormatColumn](https://www.adaptabletools.com/docs/reference/initialstate.md#formatcolumn) | [`FormatColumnState`](https://www.adaptabletools.com/docs/reference/formatcolumnstate.md) | Collection of *FormatColumn* objects that will style an entire column either fully or using a Condition | | [FreeTextColumn](https://www.adaptabletools.com/docs/reference/initialstate.md#freetextcolumn) | [`FreeTextColumnState`](https://www.adaptabletools.com/docs/reference/freetextcolumnstate.md) | Collection of *FreeText* objects so users can make their own notes in bespoke columns that will get stored with their state (and not with the DataSource). Useful if needing a 'Comments' column. | | [Layout](https://www.adaptabletools.com/docs/reference/initialstate.md#layout) | [`LayoutState`](https://www.adaptabletools.com/docs/reference/layoutstate.md) | Collection of *Layouts* to name (and manage) sets of column visibility, order, grouping, sorts, aggregations, filters etc. | | [NamedQuery](https://www.adaptabletools.com/docs/reference/initialstate.md#namedquery) | [`NamedQueryState`](https://www.adaptabletools.com/docs/reference/namedquerystate.md) | Named Queries available for use across multiple AdapTable Modules | | [Note](https://www.adaptabletools.com/docs/reference/initialstate.md#note) | [`NoteState`](https://www.adaptabletools.com/docs/reference/notestate.md) | Collection of personal Notes that are edited at Cell level | | [PlusMinus](https://www.adaptabletools.com/docs/reference/initialstate.md#plusminus) | [`PlusMinusState`](https://www.adaptabletools.com/docs/reference/plusminusstate.md) | Plus Minus module: nudge rules. Optional `IncrementKey` / `DecrementKey` on each nudge accept either a single key or a keyboard shortcut combination (e.g. `shift+Enter`); when omitted, `AdaptableOptions.plusMinusOptions` applies, then `+` / `-`. | | [QuickSearch](https://www.adaptabletools.com/docs/reference/initialstate.md#quicksearch) | [`QuickSearchState`](https://www.adaptabletools.com/docs/reference/quicksearchstate.md) | Configues how Quick Search will run i.e. how and whether to highlight matching cells and to filter out non-matching rows | | [Shortcut](https://www.adaptabletools.com/docs/reference/initialstate.md#shortcut) | [`ShortcutState`](https://www.adaptabletools.com/docs/reference/shortcutstate.md) | Collection of *Shortcut* objects to aid data entry and prevent 'fat finger' issues | | [StatusBar](https://www.adaptabletools.com/docs/reference/initialstate.md#statusbar) | [`StatusBarState`](https://www.adaptabletools.com/docs/reference/statusbarstate.md) | Configures the Adaptable Status Bar | | [StyledColumn](https://www.adaptabletools.com/docs/reference/initialstate.md#styledcolumn) | [`StyledColumnState`](https://www.adaptabletools.com/docs/reference/styledcolumnstate.md) | Collection of Special Column Styles | | [Theme](https://www.adaptabletools.com/docs/reference/initialstate.md#theme) | [`ThemeState`](https://www.adaptabletools.com/docs/reference/themestate.md) | Specifies current Theme and lists User and System themes available for selection | | [ToolPanel](https://www.adaptabletools.com/docs/reference/initialstate.md#toolpanel) | [`ToolPanelState`](https://www.adaptabletools.com/docs/reference/toolpanelstate.md) | Sets order & visibility of Tool Panel controls in AdapTable ToolPanel (on right of grid) | | [UserInterface](https://www.adaptabletools.com/docs/reference/initialstate.md#userinterface) | [`UserInterfaceState`](https://www.adaptabletools.com/docs/reference/userinterfacestate.md) | Controls the visibility of AdapTable UI elements (Dashboard, Tool Panel, Status Bar, Menus etc.) | Initial Adaptable State can be provided either as pure JSON or a url string to a file containing the JSON ## How It Works When AdapTable is first loaded, the Initial Adaptable State is read into memory and then stored. This storage can be locally or remotely depending on the [AdapTable State Persistence](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence/index.md) During that initial session AdapTable will merge the Initial Adaptable State with any user state that was created. Subsequently, each time the application is launched, that User State is retrieved and the particular AdapTable instance is pre-populated with it. Although you can construct Inital State by hand, its often easier when building "complex" items like [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) to create them in the GUI at design time and then copy and paste the resulting state ## Updating Initial Adaptable State As the name implies, the concept behind Initial Adaptable State is that it provides - at design-time - the objects, entitlements and theme for **initial** use of the Application. It is read once and merged into the user's Adaptable State, and then any run-time changes which users make will form part of their State and be continually updated. But sometimes, after the application has gone live, developers might want to update one section in Initial Adaptable State while ensuring that the rest of the user's State remains untouched. ### Revision Property This can be accomplished through the `Revision` property in [`BaseState`](https://www.adaptabletools.com/docs/reference/basestate.md) `BaseState` is the base interface for all User State sections The `Revision` property is defined as follows: ```ts Revision?: number | { Key: number; UpdateStrategy: 'Override' | 'KeepUserDefined' }; ``` ### Replacing an Entire Section As can be seen the Revision object can, in its simplified form, be a number. In this scenario, if you increment (or provide from new) the revision number in a section of Initial State, AdapTable will **replace** that section (but only that section) in the user's State with the new InitialState. Providing a number is **replace only** with no merging taking place ```ts export default { CustomSort: { // This replaces existing Custom Sort section in User State with section provided here // (if the Revision Number - of 2 - is higher than the one currently in User State) // All other sections of Initial Adaptable Stateg will remain untouched Revision: 2, CustomSorts: [ { Name: 'CustomSort-Rating', ColumnId: 'Rating', SortedValues: ['AAA', 'AA+', 'AA', 'AA-'], // etc. }, ], }, } as InitialState; ``` ### Updating Part of a Section For a more granular approach you can provide an object which contains 2 properties: - `Key` of type number - `UpdateStrategy` which can have 2 values: - `Override` - the provided Initial State will override whatever is stored in AdapTable State for that section - `KeepUserDefined` - the provided Initial State will be added to what is stored in Adaptable State ```ts export default { CustomSort: { // This adds a new item to the Custom Sort section of User State // The UpdateStrategy property is set to 'KeepUserDefined' (rather than 'Override') // so any user-created items in Custom Sort will not be replaced Revision: {Key: 5, UpdateStrategy: 'KeepUserDefined'}, CustomSorts: [ { Name: 'CustomSort-Rating', ColumnId: 'Rating', SortedValues: ['AAA', 'AA+', 'AA', 'AA-'], // etc. }, ], }, } as InitialState; ``` ## Providing Custom Data The [Application State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-custom/index.md) section of Adaptable State contains an `ApplicationDataEntries` array. This is essentially a set of key / value pairs that you can populate with any data that you want and which AdapTable will store in its state. This is a useful way to store additional data with your Initial Adaptable State e.g. user location, last updated time etc. ## Adaptable Objects All objects in Initial Adaptable State inherit from [`AdaptableObject`](https://www.adaptabletools.com/docs/reference/adaptableobject.md). - AdapTable Objects comprise most of the objects supplied in [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md) like Format Column - However it also includes those objects which appear as Initial State properties (e.g. [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md), [Button](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md) etc.) ### Adaptable Object Properties The `AdaptableObject` is defined as follows: | Property | Type | Description | | --- | --- | --- | | [AdaptableVersion](https://www.adaptabletools.com/docs/reference/adaptableobject.md#adaptableversion) | [`AdaptableVersion`](https://www.adaptabletools.com/docs/reference/adaptableversion.md) | Current AdapTable version | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/adaptableobject.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | [Metadata](https://www.adaptabletools.com/docs/reference/adaptableobject.md#metadata) | `any` | Optional metadata associated with the object; can be used to store additional information or configuration | | [Source](https://www.adaptabletools.com/docs/reference/adaptableobject.md#source) | `'InitialState' \| 'User'` | Source of state object: 'InitialState' if provided via `AdaptableOptions.initialState`, 'User' or undefined for runtime state | | [Tags](https://www.adaptabletools.com/docs/reference/adaptableobject.md#tags) | [`AdaptableObjectTag`](https://www.adaptabletools.com/docs/reference/adaptableobjecttag.md)`[]` | List of Tags associated with the Object; often used for extending Layouts | #### Uuid The `Uuid` property is of type `TypeUuid` and used for easy identification of objects. It allows AdapTable instances to share state and inform each other of CRUD events on an item. If [Team Sharing](https://www.adaptabletools.com/docs/handbook-team-sharing/index.md) is enabled, any Adaptable Object can easily be shared at run-time between colleagues - Do **not** set this property when writing objects in [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) - Instead, it will be set by AdapTable at run-time when the Initial State is first read #### IsReadOnly [Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) in AdapTable typically operate at the [Module](https://www.adaptabletools.com/docs/technical-reference-adaptable-modules/index.md) level. Each Module can be set to be `Full`, `ReadOnly` or `Hidden` However, sometimes a use case demands that while the Module has a 'Full' entitlement (i.e. it is editable), one particular object must be ReadOnly (i.e. cannot be deleted). This property is designed for precisely this reason, and it will overrride the 'Full' Entitlement in the Module. - There is no property for the opposite use case - You cannot change an AdapTable object to be `Full` where the Module's Entitlement is `ReadOnly` #### Source The `Source` property is applied by AdapTable and defines where the object was **first** created. Do not provide a value for this property in [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md) as it will be set by AdapTable at run-time AdapTable will dynamically set this property to be one of 2 values: - `InitialState` - the object was initially provided in Initial Adaptable State - `User` - the object was created by the user at run-time in the AdapTable UI If an object is first supplied in Initial State and then later amended by the User in the UI, the value of the `Source` property will remain unchanged #### Object Tags Every Adaptable Object has a `Tags` property (of type [`AdaptableObjectTag`](https://www.adaptabletools.com/docs/reference/adaptableobjecttag.md)). A Tag is a very simple object that just contains a string value. However it allows you to provide additional information to any object that you create. - The main use case of Tags is to **limit** the scope of the Object to particular [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) - See [Extending Layouts](https://www.adaptabletools.com/docs/handbook-layouts-extending/index.md) for full instructions how to achieve this #### Object Meta Data Every Adaptable Object has a `MetaData` property. This is designed to allow developers to assign custom properties / data to the object. This is most commonly used to additional extra information to [Layouts](https://www.adaptabletools.com/docs/handbook-layouts-extending/index.md) (e.g. team) #### AdaptableVersion Every Adaptable Object states which version of AdapTable is being run. This is useful if you have multiple applications running, using different AdapTable versions. ### Suspending Objects To DO - go to link --- # State Management Module Canonical page: https://www.adaptabletools.com/docs/dev-guide-adaptable-state-management - The State Management Module allows users to manage AdapTable State at run-time AdapTable State usually just 'happens' without the User being aware of the persistence mechanism or needing to do anything in particular. However AdapTable provides the State Management Module to assist managing Adaptable State in the UI. It primarily allows users to import and export AdapTable State. It's functionality can be accessed in 3 UI components: - The `Manage State` section in the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md) - The `Manage State` [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md) in the Dashboard - The `Manage State` [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) in the AdapTable Tool Panel Component - It is unlikely that you will want all your users to have access to this feature at run-time - If so, set the [Entitlement](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) to `Hidden` for those users who do not need this feature ## State Functionality All 3 Manange State components contain 4 State-related options: - **Clearing User State** This will re-load the initial [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) that was provided - If using [Local Storage](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence/index.md#local-storage), AdapTable will automatically clear what is in the User's State - If using [Remote Storage](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence/index.md#remote-storage), AdapTable will invoke the `clearState` function that was provided at design-time - **Loading Initial Adaptable State** (from a JSON file) - **Exporting the AdapTable State** - to Clipboard, Console or JSON - **Exporting Initial Adaptable State** - to Clipboard, Console or JSON **Example: State Management Module** Managing Adaptable State with State Management Module - This demo opens the State Management page of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'State Management Module', initialState: { Dashboard: { ModuleButtons: ['StateManagement', 'SettingsPanel'], Tabs: [ { Name: 'State', Toolbars: ['StateManagement'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'language', 'github_stars', 'license', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'github_watchers', 'description', 'open_issues_count', ], AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { adaptableApi.settingsPanelApi.openSettingsPanel('StateManagement'); }; ``` --- # Migrating Adaptable State Canonical page: https://www.adaptabletools.com/docs/dev-guide-adaptable-state-migrating-state - AdapTable provides an automated State Upgrade Process to manage the transitions from different version of State - This is particularly useful when a major version has introduced breaking changes - Users can opt out from this and choose manually to upgrade their state. We try hard to ensure that all changes to the `InitialState` object are fully backwardly compatible. However, very occasionally, the implementation of an enhancement request, requires an update to Initial State that introduces a **breaking change**. Initial State related breaking changes only happen once a year at most, and only in a Major Version release ## Automatic State Migration AdapTable includes an automated State Upgrade Process that seamlessly converts any existing **_old_** Adaptable State to the **_new_** AdapTable State format. - This upgrade process runs silently in the background each time AdapTable starts - However, its effects are most significant when the application loads for the first time after a major version update The upgrade process operates automatically without any user intervention: 1. Detects outdated Adaptable State 2. Performs necessary updates and conversions 3. Saves the updated State for future use Users will experience no disruption as all migrations happen transparently in the background. ## Manual State Migration Developers can choose to handle state migrations manually by disabling the automatic process. This is done by setting `autoMigrateState` in [State Options](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-technical-reference/index.md) to *false*. ### `autoMigrateState` Automatically migrates Adaptable State between Old and New Versions This property decides whether AdapTable automatically updates the AdapTable State between major versions. This ensures that all breaking changes are dealt with in a way that is hidden from the user. Developer can choose to update State manually by setting this property to *false*. ```ts {3} const adaptableOptions: AdaptableOptions = { stateOptions: { autoMigrateState: false }, }; ``` Developers can, instead, programmatically upgrade their AdapTable State at any time, by calling the static `AdaptableUpgradeHelper.migrateAdaptableState` function. ### Guide to Migrating State Manually The static `migrateAdaptableState` function in `AdaptableUpgradeHelper` is defined as follows: ```ts static migrateAdaptableState(state: AdaptableState, config: UpgradeConfig): AdaptableState ``` As can be seen it takes 2 properties (some AdaptableState, and an `UpgradeConfig` Object) and returns the updated State. The [`UpgradeConfig`](https://www.adaptabletools.com/docs/reference/upgradeconfig.md) object allows you to define which versions to upgrade and provide a custom logger if needed: | Property | Type | Description | Default | | --- | --- | --- | --- | | [fromVersion](https://www.adaptabletools.com/docs/reference/upgradeconfig.md#fromversion) | `number` | AdapTable version to upgrade from | | | [logger](https://www.adaptabletools.com/docs/reference/upgradeconfig.md#logger) | `MigrationLogger` | The logger object | The console object | | [toVersion](https://www.adaptabletools.com/docs/reference/upgradeconfig.md#toversion) | `number` | AdapTable version to upgrade to | The current version | So to perform a custom migration between specific versions - in this example from Version 20 to Version 21 - and additionally modify state properties, add custom properties, or remove existing ones would be: ```ts {2,8} stateOptions: { autoMigrateState: false, applyState: (state: AdaptableState) => { const config: UpgradeConfig = { fromVersion: 20, toVersion: 21, }; const v21_state = AdaptableUpgradeHelper.migrateAdaptableState(state, config); // perform additional, custom/application specific state migration here return v21_state; } } ``` See the full guide to [Persisting State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence/index.md#applystate) for more details on how the `applyState` function works --- # AdapTable State Persistence Guide Canonical page: https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence - By default, AdapTable State is saved to local storage and users need to do anything - In practice most users use remote storage which AdapTable provides via a series of functions in State Options AdapTable State is designed to be persisted allowing for a seamless user experience between sessions. ## Local Storage By default, AdapTable State is stored in the browser's local storage. This is done using the unique `adaptableStateKey` property provided in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md). If using Local Storage, all user state will be lost each time the user clear's the browser cache or switches computers In practice, very few production users of AdapTable use local storage as their storage mechanism. Learn more about setting the [adaptableStateKey](https://www.adaptabletools.com/docs/getting-started-adaptable-state-key/index.md) property in the Integration Guide ## Remote Storage AdapTable also enables User State to be persisted remotely in - and subsequently retrieved from - any location of the users' choice. - Most of the demos in this site use Local Storage for convenience sake - However, the overwhelming majority of real world applications that use AdapTable leverage remote storage Remote storage is accessible via a set of JavaScript functions available in [`State Options`](https://www.adaptabletools.com/docs/reference/stateoptions.md). State Options provides 5 functions which allow developers to control the management of AdapTable State and supports custom implementations and functionality for managing state: - This allows you to provide your own hydration or rehydration functionality if required - It also allows you to enrich the State when its being loaded with your own items (e.g. [Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md)) | Function | Enables | Default AdapTable Behaviour | | -------------- | ---------------------------------------------------- | ------------------------------- | | `loadState` | Customization of State loading | Loads State from local storage | | `applyState` | Hooking into State hydration | | | `saveState` | Customization of State that is about to be persisted | | | `persistState` | Customisation of State persistence | Persists State to local storage | | `clearState` | Clears all User State | Clears State from local storage | #### Remote Storage Workflow The AdapTable State flow is as follows: 1. User Loads Page --> `loadState()` state1 -> `applyState(state1)` 2. state2 ---- ADAPTABLE NOW READY WITH STATE (state2) 3. User Updates State ------ `saveState(state3)`: 4. state4 -> `persistState(state4)` ### Load State ### `loadState` Manages loading remote Adaptable State (async) [`AdaptableLoadStateFunction`](https://www.adaptabletools.com/docs/reference/adaptableloadstatefunction.md) By default, AdapTable will read and return the state that was persisted from localStorage (using the [adaptableId](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) key) `loadState` is nearly always used in conjunction with [persistState](#persiststate) - the other side of the persistence mechanism The function is of type [`AdaptableLoadStateFunction`](https://www.adaptabletools.com/docs/reference/adaptableloadstatefunction.md): ```ts export interface AdaptableLoadStateFunction { (adaptableStateFunctionConfig: AdaptableStateFunctionConfig): Promise; } ``` The function receives a [`AdaptableStateFunctionConfig`](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md) object defined as follows: | Property | Type | Description | | --- | --- | --- | | [actionName](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#actionname) | `string` | Name of the action that triggered the state change. | | [adaptableApi](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptableapi) | [`AdaptableApi`](https://www.adaptabletools.com/docs/reference/adaptableapi.md) | Adaptable API | | [adaptableContext](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | | [adaptableId](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptableid) | `string` | Id of current Adaptable instance | | [adaptableStateKey](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptablestatekey) | `string` | State Key being used | | [previousState](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#previousstate) | [`AdaptableState`](https://www.adaptabletools.com/docs/reference/adaptablestate.md) | Previous state before the action was applied. This is useful for comparing changes or reverting if necessary. | | [userName](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#username) | `string` | current Adaptable user | `loadState` can be used to load Adaptable State from the browser window object or a remote location The hydration flow is: `loadState` -> `applyState` So whatever `loadState` returns, is passed to [applyState](#applystate). ```ts stateOptions: { // loadState is used to load the Adaptable State from a remote source (firebase in this example) // It returns a promise which is resolved when the State is retrieved from firebase loadState: () => { return firebase .database() .ref(`initialState/${id}`) .once('value') .then(function (snapshot) { const str = snapshot.val(); return str ? JSON.parse(str) : {}; }); }, } ``` This function should be **asynchronous** ### Apply State ### `applyState` Allows hooking into Adaptable State hydration This function determines what state is (re)applied in AdapTable when AdapTable is initialized. The definition of the function is: ```ts applyState?: (state: any) => any; ``` This function is useful when [saveState](#savestate) was specified and added new custom properties, which will again be accessible into the `applyState` function. The hydration flow is: `loadState` -> `applyState` So whatever [loadState](#loadstate) returns, is passed to this function. This function should be **synchronous** The default implementation is to do nothing: ```ts (state) => state ``` If you used [saveState](#savestate) to add custom app-specific properties on the top-level object you returned, it's a good practice to clear these properties and just return Adaptable State from this function. ```ts adaptableOptions = { stateOptions: { saveState: (state) => { return { ...state, userSettings: { language: 'de', }, }; }, applyState: (state) => { const {userSettings, ...adaptableState} = state; // do something with userSettings here return adaptableState; }, }, }; ``` ### Save State ### `saveState` Allows customization of the Adaptable State about to be persisted [`AdaptableSaveStateFunction`](https://www.adaptabletools.com/docs/reference/adaptablesavestatefunction.md) This function allows developers to customise the AdapTable State that is going to be persisted. The function is of type [`AdaptableSaveStateFunction`](https://www.adaptabletools.com/docs/reference/adaptablesavestatefunction.md): ```ts export interface AdaptableSaveStateFunction { ( state: AdaptableState, adaptableStateFunctionConfig: AdaptableStateFunctionConfig ): any; } ``` The function receives a [`AdaptableStateFunctionConfig`](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md) object defined as follows: | Property | Type | Description | | --- | --- | --- | | [actionName](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#actionname) | `string` | Name of the action that triggered the state change. | | [adaptableApi](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptableapi) | [`AdaptableApi`](https://www.adaptabletools.com/docs/reference/adaptableapi.md) | Adaptable API | | [adaptableContext](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | | [adaptableId](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptableid) | `string` | Id of current Adaptable instance | | [adaptableStateKey](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptablestatekey) | `string` | State Key being used | | [previousState](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#previousstate) | [`AdaptableState`](https://www.adaptabletools.com/docs/reference/adaptablestate.md) | Previous state before the action was applied. This is useful for comparing changes or reverting if necessary. | | [userName](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#username) | `string` | current Adaptable user | In this case, you might find it useful to also define [applyState](#applystate) which hooks into state hydration, and gives you access to the persisted custom properties, so you can use them later in the applicaton. If you also want to modify the persistence behaviour, you should implement the [persistState](#persiststate) as well The persistence (dehydration) flow is the following: `saveState` -> `persistState` You have to make sure that the returned object is serializable with JSON.stringify - in case that it's not, you could define [persistState](#persiststate) to do a custom serialization of the object. This function should be synchronous The default implementation is to do nothing: ```ts (state) => state ``` Use this function to add other properties to Adaptable State before persistence ```ts adaptableOptions = { stateOptions: { saveState: (state) => { return { ...state, userSettings: { language: 'de', }, }; }, }, }; ``` ### Persist State ### `persistState` Enables the customization of State persistence [`AdaptablePersistStateFunction`](https://www.adaptabletools.com/docs/reference/adaptablepersiststatefunction.md) By default AdapTable stringifies the AdapTable State and puts it into the localStorage using the [adaptableId](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) key. This function can be used to change this behaviour, and to throttle state persistence or perform other actions. The function is of type [`AdaptablePersistStateFunction`](https://www.adaptabletools.com/docs/reference/adaptablepersiststatefunction.md): ```ts export interface AdaptablePersistStateFunction { ( state: AdaptableState, adaptableStateFunctionConfig: AdaptableStateFunctionConfig ): any; } ``` The function receives a [`AdaptableStateFunctionConfig`](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md) object defined as follows: | Property | Type | Description | | --- | --- | --- | | [actionName](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#actionname) | `string` | Name of the action that triggered the state change. | | [adaptableApi](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptableapi) | [`AdaptableApi`](https://www.adaptabletools.com/docs/reference/adaptableapi.md) | Adaptable API | | [adaptableContext](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | | [adaptableId](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptableid) | `string` | Id of current Adaptable instance | | [adaptableStateKey](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptablestatekey) | `string` | State Key being used | | [previousState](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#previousstate) | [`AdaptableState`](https://www.adaptabletools.com/docs/reference/adaptablestate.md) | Previous state before the action was applied. This is useful for comparing changes or reverting if necessary. | | [userName](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#username) | `string` | current Adaptable user | This function is generally used in conjunction with [loadState](#loadstate) - the other side of the persistence mechanism The persistence (dehydration) flow is: `saveState` -> `persistState`. Use `saveState` to add props to the state about to be persisted; whatever that returns is passed to `persistState` ### Clear State ### `clearState` Allows clearing of remote Adaptable State [`AdaptableClearStateFunction`](https://www.adaptabletools.com/docs/reference/adaptableclearstatefunction.md) This is an optional function which will clear out any saved remote state. It is only invoked in one place in AdapTable - inside the `reloadInitialState` function in [State API](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-technical-reference/index.md) If using local storage then AdapTable will clear this out automatically The function is of type [`AdaptableClearStateFunction`](https://www.adaptabletools.com/docs/reference/adaptableclearstatefunction.md): ```ts export interface AdaptableClearStateFunction { (adaptablestatefunctionconfig: AdaptableStateFunctionConfig): Promise; } ``` The function receives a [`AdaptableStateFunctionConfig`](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md) object defined as follows: | Property | Type | Description | | --- | --- | --- | | [actionName](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#actionname) | `string` | Name of the action that triggered the state change. | | [adaptableApi](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptableapi) | [`AdaptableApi`](https://www.adaptabletools.com/docs/reference/adaptableapi.md) | Adaptable API | | [adaptableContext](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | | [adaptableId](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptableid) | `string` | Id of current Adaptable instance | | [adaptableStateKey](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#adaptablestatekey) | `string` | State Key being used | | [previousState](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#previousstate) | [`AdaptableState`](https://www.adaptabletools.com/docs/reference/adaptablestate.md) | Previous state before the action was applied. This is useful for comparing changes or reverting if necessary. | | [userName](https://www.adaptabletools.com/docs/reference/adaptablestatefunctionconfig.md#username) | `string` | current Adaptable user | ```ts adaptableOptions = { stateOptions: { clearState: (state) => { return { ...state, userSettings: { language: 'de', }, }; }, }, }; ``` **Example: Remote State Persistence** Stores AdapTable State remotely (using Supabase) - This example illustrates how straightforward is to load/persist state from/to a remote datastore - Here we use Supabase as our persistence layer - We provide custom implementations for `loadState` and `persistState` from State Options In this demo we provide implementations for the loadState and persistState functions to connect our State to a remote Supabase datastore. Note: The state is shared with everyone who uses the same AdaptableStateKey. * Loading the state from a remote datastore - using loadState in State Options: ```ts /** * The loadState function is used to load the state * from a remote source - namely Supabase in this example * * It returns a promise which is resolved when the state object is * retrieved from Supabase. */ loadState: (config: AdaptableStateFunctionConfig) => { return supabaseService.loadAdaptableState(config.adaptableStateKey); } ``` * Persist state changes to a remote datastore - using persistState in State Options: ```ts /** * The persistState function is called with the state that needs to be persisted. * By default, state is persisted in localStorage, but this example * illustrates how you can persist it to a remote datastore (Supabase, etc) */ persistState: ( state: Partial, config: AdaptableStateFunctionConfig ) => { return supabaseService.persistAdaptableState( state, config.adaptableStateKey, config.userName ); } ``` - make any changes to the AdapTable State (e.g. change the current Layout) and then refresh the page: the changes will be retained - change the `AdaptableStateKey`: the grid will be reset to its initial state and a new state will be persisted - going back to the previous `AdaptableStateKey` will restore the previous state ```ts import { AdaptableApi, AdaptableButton, AdaptableOptions, AdaptableState, AdaptableStateFunctionConfig, CustomToolbarButtonContext, } from '@adaptabletools/adaptable'; import {SupabasePersistenceService} from './SupabasePersistenceService'; import {WebFramework} from 'rowData'; const supabaseService = new SupabasePersistenceService(); export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Using Supabase State', adaptableStateKey: 'docs/PersistentStateDemo', stateOptions: { /** * The loadState function is used to load the state * from a remote source - namely Supabase in this example * * It returns a promise which is resolved when the state object is * retrieved from Supabase. */ loadState: (config: AdaptableStateFunctionConfig) => { return supabaseService.loadAdaptableState(config.adaptableStateKey); }, /** * The persistState function is called with the state that needs to be persisted. * By default, state is persisted in localStorage, but this example * illustrates how you can persist it to a remote datastore (Supabase, etc) */ persistState: ( state: Partial, config: AdaptableStateFunctionConfig ) => { return supabaseService.persistAdaptableState( state, config.adaptableStateKey, config.userName ); }, }, dashboardOptions: { customToolbars: [ { name: 'StateKeyConfigInput', render: ({adaptableApi}: {adaptableApi: AdaptableApi}) => { const stateKeyValue = adaptableApi.optionsApi.getAdaptableStateKey(); return ` `; }, }, { name: 'StateKeyConfigButton', toolbarButtons: [ { label: 'Set Key & Refresh State', buttonStyle: { tone: 'info', variant: 'raised', }, onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { const element: any = document.getElementById('stateKeyValueInput'); const stateKeyValue = element!.value; if (stateKeyValue) { context.adaptableApi.stateApi.setAdaptableStateKey( stateKeyValue ); } }, }, ], }, ], }, initialState: { Dashboard: { Tabs: [ { Name: 'State Settings', Toolbars: ['StateKeyConfigInput', 'StateKeyConfigButton'], }, ], PinnedToolbars: ['Layout'], }, Theme: {CurrentTheme: 'dark'}, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-github_stars', Rule: { Predicates: [ { PredicateId: 'GreaterThan', Inputs: [1000], }, ], }, Style: { BackColor: 'Yellow', ForeColor: 'Black', }, Scope: { ColumnIds: ['github_stars'], }, }, ], }, Layout: { CurrentLayout: 'Pivot Layout', Layouts: [ { Name: 'Pivot Layout', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ {ColumnId: 'github_watchers', AggFunc: 'sum'}, {ColumnId: 'github_stars', AggFunc: 'sum'}, ], }, { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', 'has_wiki', 'pushed_at', 'open_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { adaptableApi.eventApi.on('AdaptableStateChanged', stateChangedEvent => { if (stateChangedEvent.actionName === 'LOAD_STATE') { adaptableApi.alertApi.showAlert( 'State Loaded', `State loaded successfully: ${stateChangedEvent.adaptableStateKey}`, 'Success' ); } }); }; ``` ```ts import {createClient, SupabaseClient} from '@supabase/supabase-js'; import {dbConfig} from './dbConfig'; /** * This is a simple implementation of the Adaptable Persistence Service that uses Supabase as the underlying storage mechanism. * * @see {@link https://supabase.com/} */ export class SupabasePersistenceService { private supabase: SupabaseClient; private stateTable = 'adaptable_state_docs'; private debugMode: boolean; constructor(config?: {debugMode: boolean}) { this.supabase = createClient( dbConfig.supabaseUrl, dbConfig.supabaseKey ); this.debugMode = !!config?.debugMode; } async loadAdaptableState(stateKey: string): Promise { const {data, error} = await this.supabase .from(this.stateTable) .select() .eq('state_key', stateKey); if (error) { this.log(`LOAD_STATE::${stateKey}`, 'ERROR'); console.error(error); return {}; } // @ts-ignore const stateTextValue = data?.[0]?.state_value ?? '{}'; this.log(`LOAD_STATE::${stateKey}`, data); return JSON.parse(stateTextValue); } async persistAdaptableState( state: any, stateKey: string, userName: string ): Promise { const stateTextValue = JSON.stringify(state); const {error} = await this.supabase.from(this.stateTable).upsert({ state_key: stateKey, state_value: stateTextValue, last_changed_by: userName, }); if (error) { this.log(`PERSIST_STATE::${stateKey}`, 'ERROR'); console.error(error); } else { this.log(`PERSIST_STATE::${stateKey}`, state); } } async clearAdaptableState(stateKey: string, userName: string): Promise { const {error} = await this.supabase.from(this.stateTable).upsert({ state_key: stateKey, state_value: '{}', change_counter: 0, last_changed_by: userName, }); if (error) { this.log(`CLEAR_STATE::${stateKey}`, 'ERROR'); console.error(error); } else { this.log(`CLEAR_STATE::${stateKey}`); } } async resetEntireAdaptableState(): Promise { // delete all rows in table const {error} = await this.supabase.from(this.stateTable).delete(); if (error) { console.error(error); } else { this.log(`RESET_STATE`); } } private log(...params: any) { if (!this.debugMode) { return; } console.log(...params); } } /** * Database Table Schema */ interface Database { public: { Tables: { adaptable_state_docs: { Row: { change_counter: number | null; created_at: string; last_changed_by: string | null; state_key: string; state_value: string | null; updated_at: string | null; }; Insert: { change_counter?: number | null; created_at?: string; last_changed_by?: string | null; state_key: string; state_value?: string | null; updated_at?: string | null; }; Update: { change_counter?: number | null; created_at?: string; last_changed_by?: string | null; state_key?: string; state_value?: string | null; updated_at?: string | null; }; Relationships: []; }; }; Views: { [_ in never]: never; }; Functions: { [_ in never]: never; }; Enums: { [_ in never]: never; }; CompositeTypes: { [_ in never]: never; }; }; } ``` ```ts export const dbConfig = { supabaseUrl: 'https://uqbssslumnnwqwcmdcoc.supabase.co', supabaseKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVxYnNzc2x1bW5ud3F3Y21kY29jIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDI1NTA4MzQsImV4cCI6MjAxODEyNjgzNH0.nyCiCwNhgQtY3TF3VmJlEI22YC8YpH0DlEC_cb9tamM', }; ``` ### Debouncing State Changes By default AdapTable will debounce `saveState` and `persistState` function calls for 400 miliseconds. This enables grouping multiple sequential calls into single one. A good analogy might be how lift / elevator doors work This can be changed using the `debounceStateDelay` property in State Options. ### `debounceStateDelay` Delay (in ms) to debounce saveState and persistState calls Provides a debounce delay other than the default of 400ms. The maximum value allowed is 1000ms, at which point the save/persist calls will happen anyway ```ts {4} // Wait 3/4 of a second before saving and persisting state const adaptableOptions: AdaptableOptions = { stateOptions = { debounceStateDelay: 750 } }; ``` ## Managing Multiple States The Sandpack below is implemented as a **React** app (login control above the grid; switching users re-initialises AdapTable with new `AdaptableOptions`). It runs the same way whichever **framework picker** flavour you have selected. The `stateOptions`, `entitlementOptions`, and `dashboardOptions` shown in the walkthrough apply equally to AdapTable TypeScript, React, Angular, and Vue — only the surrounding application wiring differs. **Example: Load & persist state based on user identity/role** Loading and persisting state based on user identity/role - This example shows how to load & persist state based on user identity/role; (the persistence uses [Supabase](https://supabase.io/), but any storage provider works (e.g. Firebase, AWS S3, etc.). - It also showcases user specific [Permissions (Entitlements)](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) and how to use them to control access to AdapTable features. - The demo showcases 3 different users: - **Guest** (not logged in) - any changes they make will not be persisted and will be lost when the page is refreshed - all AdapTable features are available but only in read-only mode - __Alice__ - any changes she makes will be persisted and will be available only to her - all AdapTable features are available and editable, except for the `StyledColumn` module which is in read-only mode - __Bob__ - any changes he makes will be persisted and will be available only to him - all AdapTable features are available and editable, except for the `Alert` module which is hidden - The logged in users (`Alice` and `Bob`) can revert to the Initial Adaptable State by clicking the `Reset State` button in the Dashboard. ### Expand to see how the State Management and Entitlements is configured __1.__ The current user information is loaded/set __before AdapTable is initialised__ - in this case (a React app) in a local state variable called `currentUser` __2.__ The Initial Adaptable State is set based on the current user information ```ts {4,16} export const buildAdaptableState = (userName: 'Alice' | 'Bob' | 'GUEST') => { const initialConfigForUser = INITIAL_CONFIGS[userName]; // merge common config with user specific config const initialConfig = { ...COMMON_CONFIG, ...initialConfigForUser, }; // the rest of AdaptbleOptions is the same for all users // we handle the user specific behaviour via callbacks const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'User Specific State Demo', userName: userName, adaptableStateKey: 'docs/userSpecificStateDemo', initialState: initialConfig, // ... }; // ... }; ``` __3.__ The two main state management functions (`loadState` and `saveState`) are implemented (overwriting the default ones based on `localStorage`): - non-logged in users (`Guest`) will not have their state persisted at all - logged in users (`Alice` and `Bob`) will have their state persisted in Supabase - the state key is derived from the username, ensuring that each user has their own distinct state ```ts {2,8,12,18} stateOptions: { loadState: (config: AdaptableStateFunctionConfig) => { if (config.userName === 'GUEST') { // no persistent state for non-logged in users return Promise.resolve({}); } // state key is based on user name const stateKey = `${config.adaptableStateKey}/${config.userName}`; return supabaseService.loadAdaptableState(stateKey); }, persistState: (state: any, config: AdaptableStateFunctionConfig) => { if (config.userName === 'GUEST') { // no persistent state for non-logged in users return Promise.resolve(); } // state key is based on user name const stateKey = `${config.adaptableStateKey}/${config.userName}`; return supabaseService.persistAdaptableState( state, stateKey, config.userName ); } ``` __4.__ The `Clear state` button which is available to logged in users (`Alice` and `Bob`) simply makes use of the extensive Adaptable API: ```ts {3,4,9,13} onClick: (_button, context) => { // clear remote state // alternatively, we could also provide a `StateOptions.clearState()` function with the same implementation // if provided, it will be called automatically by the `reloadInitialState()` function const optionsApi = context.adaptableApi.optionsApi; const stateKey = `${optionsApi.getAdaptableStateKey()}/${ context.userName }`; supabaseService.clearAdaptableState(stateKey, context.userName); // reload local state const stateApi = context.adaptableApi.stateApi; stateApi.reloadInitialState(); } ``` __5.__ The `Entitlements` are configured based on the current user information: ```ts {2,8} entitlementOptions: { defaultAccessLevel: context => { if (context.userName === 'GUEST') { return 'ReadOnly'; } return 'Full'; }, moduleEntitlements: context => { if ( context.userName === 'Alice' && context.adaptableModule === 'StyledColumn' ) { return 'ReadOnly'; } if (context.userName === 'Bob' && context.adaptableModule === 'Alert') { return 'Hidden'; } return context.defaultAccessLevel; } } ``` - Log in as `Alice` or `Bob` to see how the state is persisted distinctively for each user by making various changes to the grid and then refreshing the page - e.g. change the current Layout (sorting/adding/hiding columns), add a new FormatColumn, etc. - Reset the state by clicking the `Reset State` button in the Dashboard at any time - Navigate to the `StyledColumn` module and try to edit the existing style (only `Alice` will not be able to do this) ```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 {buildAdaptableState} from './buildAdaptableState'; import {SelectUserComponent} from './SelectUserComponent'; const App: React.FunctionComponent = () => { const adaptableApiRef = React.useRef(null); const availableUsers = ['Alice', 'Bob']; const [currentUser, setCurrentUser] = useState<'Alice' | 'Bob' | 'GUEST'>( 'GUEST' ); const adaptableOptions = buildAdaptableState(currentUser); const agGridOptions = {...gridOptions}; return (
{ setCurrentUser(user || 'GUEST'); }}>
{ // save a reference to adaptable api adaptableApiRef.current = adaptableReadyInfo.adaptableApi; onAdaptableReady(adaptableReadyInfo); }}>
); }; export default App; ``` ```ts import { AdaptableOptions, AdaptableStateFunctionConfig, InitialState, } from '@adaptabletools/adaptable-react-aggrid'; import {SupabasePersistenceService} from './SupabasePersistenceService'; const supabaseService = new SupabasePersistenceService(); export const buildAdaptableState = (userName: 'Alice' | 'Bob' | 'GUEST') => { const initialStateForUser = INITIAL_STATES[userName]; // merge common state with user specific state const initialState = { ...COMMON_STATE, ...initialStateForUser, }; // the rest of AdaptbleOptions is the same for all users // we handle the user specific behaviour via callbacks const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'User Specific State Demo', userName: userName, adaptableStateKey: 'docs/userSpecificStateDemo', initialState, stateOptions: { loadState: (config: AdaptableStateFunctionConfig) => { if (config.userName === 'GUEST') { // no persistent state for non-logged in users return Promise.resolve({}); } // state key is based on user name const stateKey = `${config.adaptableStateKey}/${config.userName}`; return supabaseService.loadAdaptableState(stateKey); }, persistState: (state: any, config: AdaptableStateFunctionConfig) => { if (config.userName === 'GUEST') { // no persistent state for non-logged in users return Promise.resolve(); } // state key is based on user name const stateKey = `${config.adaptableStateKey}/${config.userName}`; return supabaseService.persistAdaptableState( state, stateKey, config.userName ); }, }, entitlementOptions: { defaultAccessLevel: context => { if (context.userName === 'GUEST') { return 'ReadOnly'; } return 'Full'; }, moduleEntitlements: context => { if ( context.userName === 'Alice' && context.adaptableModule === 'StyledColumn' ) { return 'ReadOnly'; } if (context.userName === 'Bob' && context.adaptableModule === 'Alert') { return 'Hidden'; } return context.defaultAccessLevel; }, }, dashboardOptions: { buttonsLocation: 'left', customDashboardButtons: [ { label: (_button, context) => `Reset remote state for ${context.userName}`, onClick: (_button, context) => { // clear remote state // alternatively, we could also provide a `StateOptions.clearState()` function with the same implementation // if provided, it will be called automatically by the `reloadInitialState()` function const optionsApi = context.adaptableApi.optionsApi; const stateKey = `${optionsApi.getAdaptableStateKey()}/${ context.userName }`; supabaseService.clearAdaptableState(stateKey, context.userName); // reload local state const stateApi = context.adaptableApi.stateApi; stateApi.reloadInitialState(); }, buttonStyle: { variant: 'raised', tone: 'warning', }, hidden: (_button, context) => { return context.userName === 'GUEST'; }, }, ], }, }; return adaptableOptions; }; const INITIAL_STATES: Record<'Alice' | 'Bob' | 'GUEST', InitialState> = { Alice: { Theme: { Revision: 1, CurrentTheme: 'light', }, Dashboard: { Revision: 1, DashboardTitle: 'Alice Grid Data', Tabs: [ { Name: 'Default', Toolbars: ['Layout', 'Export'], }, ], PinnedToolbars: ['GridFilter'], }, Layout: { Revision: 1, CurrentLayout: 'Popular Frameworks', Layouts: [ { Name: 'Popular Frameworks', TableColumns: [ 'name', 'language', 'github_stars', 'created_at', 'updated_at', 'pushed_at', 'github_watchers', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', ], ColumnFilters: [ { ColumnId: 'github_stars', Predicates: [ { PredicateId: 'GreaterThan', Inputs: [50000], }, ], }, ], }, ], }, StyledColumn: { Revision: 1, StyledColumns: [ { Name: 'language Badge', ColumnId: 'language', BadgeStyle: { Badges: [ { PillStyle: { BackColor: '#a52a2a', ForeColor: '#ffffe0', }, Predicate: { PredicateId: 'Is', Inputs: ['TypeScript'], }, }, { PillStyle: { BackColor: '#32cd32', ForeColor: '#000000', }, Predicate: { PredicateId: 'Is', Inputs: ['JavaScript'], }, }, ], }, }, ], }, }, Bob: { Theme: { Revision: 1, CurrentTheme: 'dark', }, Dashboard: { Revision: 1, DashboardTitle: 'Bob Grid Data', Tabs: [ { Name: 'Default', Toolbars: ['Layout', 'Alert'], }, ], PinnedToolbars: ['QuickSearch'], }, Layout: { Revision: 2, CurrentLayout: 'TypeScript Frameworks', Layouts: [ { Name: 'JavaScript Frameworks', TableColumns: [ 'name', 'description', 'github_stars', 'open_issues_count', 'github_watchers', 'updated_at', 'license', 'created_at', 'has_wiki', 'pushed_at', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], ColumnFilters: [ { ColumnId: 'language', Predicates: [ { PredicateId: 'Is', Inputs: ['JavaScript'], }, ], }, ], }, ], }, StyledColumn: { Revision: 1, StyledColumns: [ { Name: 'open_issues_count Gradient', ColumnId: 'open_issues_count', GradientStyle: { CellRanges: [ { Min: 'Col-Min', Max: 'Col-Max', Color: '#a52a2a', }, ], }, }, ], }, }, GUEST: { Theme: { Revision: 1, CurrentTheme: 'dark', }, Dashboard: { Revision: 1, DashboardTitle: 'Guest Grid Data', }, Layout: { Revision: 2, CurrentLayout: 'Table Layout', Layouts: [ { Name: 'Table Layout', TableColumns: [ 'name', 'language', 'github_stars', 'license', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'github_watchers', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], }, ], }, }, }; const COMMON_STATE: InitialState = { FormatColumn: { Revision: 1, FormatColumns: [ { Name: 'formatColumn-date', Scope: { DataTypes: ['date'], }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'yyyy-MM-dd', }, }, }, ], }, Layout: { Revision: 1, CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [], Name: 'Standard Layout', }, ], }, }; ``` ```ts import {createClient, SupabaseClient} from '@supabase/supabase-js'; import {dbConfig} from './dbConfig'; /** * This is a simple implementation of the Adaptable Persistence Service that uses Supabase as the underlying storage mechanism. * * @see {@link https://supabase.com/} */ export class SupabasePersistenceService { private supabase: SupabaseClient; private stateTable = 'adaptable_state_docs'; private debugMode: boolean; constructor(config?: {debugMode: boolean}) { this.supabase = createClient( dbConfig.supabaseUrl, dbConfig.supabaseKey ); this.debugMode = !!config?.debugMode; } async loadAdaptableState(stateKey: string): Promise { const {data, error} = await this.supabase .from(this.stateTable) .select() .eq('state_key', stateKey); if (error) { this.log(`LOAD_STATE::${stateKey}`, 'ERROR'); console.error(error); return {}; } // @ts-ignore const stateTextValue = data?.[0]?.state_value ?? '{}'; this.log(`LOAD_STATE::${stateKey}`, data); return JSON.parse(stateTextValue); } async persistAdaptableState( state: any, stateKey: string, userName: string ): Promise { const stateTextValue = JSON.stringify(state); const {error} = await this.supabase.from(this.stateTable).upsert({ state_key: stateKey, state_value: stateTextValue, last_changed_by: userName, }); if (error) { this.log(`PERSIST_STATE::${stateKey}`, 'ERROR'); console.error(error); } else { this.log(`PERSIST_STATE::${stateKey}`, state); } } async clearAdaptableState(stateKey: string, userName: string): Promise { const {error} = await this.supabase.from(this.stateTable).upsert({ state_key: stateKey, state_value: '{}', change_counter: 0, last_changed_by: userName, }); if (error) { this.log(`CLEAR_STATE::${stateKey}`, 'ERROR'); console.error(error); } else { this.log(`CLEAR_STATE::${stateKey}`); } } async resetEntireAdaptableState(): Promise { // delete all rows in table const {error} = await this.supabase.from(this.stateTable).delete(); if (error) { console.error(error); } else { this.log(`RESET_STATE`); } } private log(...params: any) { if (!this.debugMode) { return; } console.log(...params); } } /** * Database Table Schema */ interface Database { public: { Tables: { adaptable_state_docs: { Row: { change_counter: number | null; created_at: string; last_changed_by: string | null; state_key: string; state_value: string | null; updated_at: string | null; }; Insert: { change_counter?: number | null; created_at?: string; last_changed_by?: string | null; state_key: string; state_value?: string | null; updated_at?: string | null; }; Update: { change_counter?: number | null; created_at?: string; last_changed_by?: string | null; state_key?: string; state_value?: string | null; updated_at?: string | null; }; Relationships: []; }; }; Views: { [_ in never]: never; }; Functions: { [_ in never]: never; }; Enums: { [_ in never]: never; }; CompositeTypes: { [_ in never]: never; }; }; } ``` ```ts import React, {ChangeEventHandler, FC, useState} from 'react'; interface SelectUserComponentProps { availableUsers: string[]; onCurrentUserChange: (user?: string) => void; } export const SelectUserComponent: FC = ({ availableUsers, onCurrentUserChange, }) => { const [selectedUser, setSelectedUser] = useState(); const [currentUser, setCurrentUser] = useState(); const handleUserSelect: ChangeEventHandler = event => { const selectedValue = event.target.value; setSelectedUser(selectedValue === '' ? undefined : selectedValue); }; const handleLogin = () => { if (selectedUser) { setCurrentUser(selectedUser); onCurrentUserChange(selectedUser); } }; const handleLogout = () => { setSelectedUser(undefined); setCurrentUser(undefined); onCurrentUserChange(undefined); }; return (
{currentUser ? ( ) : ( )}
); }; ``` ```ts export const dbConfig = { supabaseUrl: 'https://uqbssslumnnwqwcmdcoc.supabase.co', supabaseKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVxYnNzc2x1bW5ud3F3Y21kY29jIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDI1NTA4MzQsImV4cCI6MjAxODEyNjgzNH0.nyCiCwNhgQtY3TF3VmJlEI22YC8YpH0DlEC_cb9tamM', }; ``` ```ts skipFile=adaptableOptions.ts ``` ## Controlling State Persistence In more advanced use cases, developers wish to control how and when State is persisted. Their aim is to suppress automatic State Persistence, and to persist state imperatively instead. There are 2 common scenarios: - suppressing **all** State Persistence and replacing it with an imperative save function - suppressing **specific** State Persistence and replacing just that with an imperative save function A popular use case is to save Layouts manually, on clicking a button, rather than automatically ### Suppressing all Persistence **Example: Persisting state imperatively** Custom State Persistence: Suppressing automatic State Persistence and imperatively persisting State - In this example we show how to suppress the automatic state persistence and imperatively persist the state - This is useful when you want to control when the state is persisted, e.g. after a user action or a specific event - This demo uses the [Adaptable Context](https://www.adaptabletools.com/docs/dev-guide-tutorial-providing-adaptable-context/index.md) to handle the interaction, but you can use any other mechanism, including your own application logic/state management - Perform any changes to the AdapTable State: e.g. change the current Layout (sorting/adding/hiding columns), add a new FormatColumn, etc. - The changes will be kept client side and will be persisted only when you click the `Persist State` button in the Dashboard - Refreshing the demo will load the last persisted state, but any changes made since the last persistence will be lost - The suppressed changes are logged in the console - Reset the state to the initial value by clicking the `Reset State` button in the Dashboard at any time ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; import { cleanupPostPersistState, customStateOptions, forcePersistState, getUnsavedChangesCounter, updateLastPersistedState, } from './stateOptions'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom State Persistence: Imperative Persist', stateOptions: customStateOptions, dashboardOptions: { customToolbars: [ { name: 'PersistState', toolbarButtons: [ { label: (_button, context) => { const {adaptableApi} = context; const unsavedStateChangesCounter = getUnsavedChangesCounter(adaptableApi); return `Persist State (Unsaved Changes = ${unsavedStateChangesCounter})`; }, onClick: (_button, context) => { const {adaptableApi} = context; forcePersistState(adaptableApi); adaptableApi.stateApi.persistAdaptableState(); }, buttonStyle: (_button, context) => { const {adaptableApi} = context; const hasUnsavedChanged = getUnsavedChangesCounter(adaptableApi) > 0; return { variant: 'raised', tone: hasUnsavedChanged ? 'warning' : 'info', }; }, }, ], title: 'Check console for more infos', }, ], customDashboardButtons: [ { tooltip: 'Reset state', icon: { name: 'refresh', }, buttonStyle: { tone: 'error', }, onClick: (_button, context) => { const {adaptableApi} = context; context.adaptableApi.stateApi.reloadInitialState(); // reset transient state values // relevant only for this demo setTimeout(() => { const state = adaptableApi.stateApi.getPersistentState(); updateLastPersistedState(state); cleanupPostPersistState(adaptableApi); }, 500); }, }, ], }, initialState: { Dashboard: { Tabs: [ { Name: 'Default', Toolbars: ['Layout', 'PersistState'], }, ], }, Theme: {CurrentTheme: 'dark'}, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-github_stars', Rule: { Predicates: [ { PredicateId: 'GreaterThan', Inputs: [1000], }, ], }, Style: { BackColor: 'Yellow', ForeColor: 'Black', }, Scope: { ColumnIds: ['github_stars'], }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', 'has_wiki', 'pushed_at', 'open_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], }, ], }, }, }; ``` ```ts import { AdaptableApi, AdaptablePersistentState, AdaptableStateFunctionConfig, StateOptions, } from '@adaptabletools/adaptable'; import {diffString} from 'json-diff'; export let LAST_PERSISTED_STATE: AdaptablePersistentState | null = null; export const customStateOptions: StateOptions = { persistState: (state, adaptableStateFunctionConfig) => { const {adaptableApi, adaptableStateKey} = adaptableStateFunctionConfig; const forcePersistState = shouldPersistState(adaptableApi); if (!forcePersistState) { let stateDelta = getStateDelta(state); if (stateDelta.trim() !== '') { console.log(`Suppressing state persistence!`); incrementUnsavedChangesCounter(adaptableApi); console.log('State diff: ', stateDelta); } return Promise.resolve(); } console.log(`Persisting state!`); localStorage.setItem(adaptableStateKey, JSON.stringify(state)); updateLastPersistedState(state); cleanupPostPersistState(adaptableApi); return Promise.resolve(true); }, loadState: (config: AdaptableStateFunctionConfig) => { console.log(`Loading state...`); return new Promise(resolve => { let state = {} as AdaptablePersistentState; try { state = JSON.parse( localStorage.getItem(config.adaptableStateKey) as string ) || {}; } catch (err) { console.log('Error loading state', err); } resolve(state); }); }, }; type CustomStateSaveContext = { FORCE_PERSIST?: boolean; UNSAVED_CHANGES_COUNTER?: number; }; export function updateLastPersistedState(state: AdaptablePersistentState) { LAST_PERSISTED_STATE = state; } export function getStateDelta(adaptableState: AdaptablePersistentState) { const lastPersistedState = LAST_PERSISTED_STATE || {}; const changedState = adaptableState; const delta = diffString(lastPersistedState, changedState); return delta; } export function shouldPersistState(adaptableApi: AdaptableApi): boolean { return ( adaptableApi.optionsApi.getAdaptableContext() .FORCE_PERSIST === true ); } export function getUnsavedChangesCounter(adaptableApi: AdaptableApi) { return ( adaptableApi.optionsApi.getAdaptableContext() .UNSAVED_CHANGES_COUNTER || 0 ); } export function incrementUnsavedChangesCounter(adaptableApi: AdaptableApi) { const unsavedChanges = getUnsavedChangesCounter(adaptableApi); adaptableApi.optionsApi.addToAdaptableContext( 'UNSAVED_CHANGES_COUNTER', unsavedChanges + 1 ); adaptableApi.dashboardApi.refreshDashboard(); } export function forcePersistState(adaptableApi: AdaptableApi) { adaptableApi.optionsApi.addToAdaptableContext( 'FORCE_PERSIST', true ); } export function cleanupPostPersistState(adaptableApi: AdaptableApi) { adaptableApi.optionsApi.addToAdaptableContext( 'FORCE_PERSIST', false ); adaptableApi.optionsApi.addToAdaptableContext( 'UNSAVED_CHANGES_COUNTER', 0 ); adaptableApi.dashboardApi.refreshDashboard(); } ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; import {updateLastPersistedState} from './stateOptions'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { const state = adaptableApi.stateApi.getPersistentState(); updateLastPersistedState(state); }; ``` ### Suppressing specific Persistence **Example: Persisting specific state slices imperatively** Custom State Persistence: Suppressing specific State changes and persisting them imperatively - In this example we show how to suppress the automatic state persistence of specific state slices (e.g. only Layouts with a specific Tag) and imperatively persist them - All other state changes will be persisted automatically as usual - This is useful when you want to control when specific changes are persisted, e.g. Layout changes, but not other changes (e.g. FormatColumns) - This demo uses the [Adaptable Context](https://www.adaptabletools.com/docs/dev-guide-tutorial-providing-adaptable-context/index.md) to handle the interaction, but you can use any other mechanism, including your own application logic/state management - Perform any changes to the 'Protected Layout': e.g. sort/filter/hide columns, etc. - All changes will NOT be persisted automatically but only when you click the `Persist State` button in the Dashboard - Refreshing the demo will load the last persisted state, but any changes made since the last persistence will be lost - The suppressed changes are logged in the console - Perform any changes to the 'Standard Layout': e.g. sort/filter/hide columns, etc. - All changes will be persisted automatically as usual - Any other changes to the AdapTable State will be persisted automatically as usual - Reset the state to the initial value by clicking the `Reset State` button in the Dashboard at any time ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; import { customStateOptions, forcePersistState, PROTECTED_LAYOUT_TAG, } from './stateOptions'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom State Persistence: Specific Changes', stateOptions: customStateOptions, dashboardOptions: { customToolbars: [ { name: 'PersistState', toolbarButtons: [ { disabled: (_button, context) => { const {adaptableApi} = context; const currentLayout = adaptableApi.layoutApi.getCurrentLayout(); return !currentLayout.Tags?.includes(PROTECTED_LAYOUT_TAG); }, label: (_button, context) => { return `Persist State (incl. Protected Layout)`; }, onClick: (_button, context) => { const {adaptableApi} = context; forcePersistState(adaptableApi); adaptableApi.stateApi.persistAdaptableState(); }, buttonStyle: (_button, context) => { return { variant: 'raised', tone: 'success', }; }, }, { label: (_button, context) => { return `Print Persisted State to Console`; }, onClick: (_button, context) => { const {adaptableApi} = context; const state = JSON.parse( localStorage.getItem( adaptableApi.optionsApi.getAdaptableStateKey() ) as string ) || {}; console.log(`Current Persisted State:`, state); }, buttonStyle: (_button, context) => { return { variant: 'raised', tone: 'accent', }; }, }, ], title: 'Check console for more infos', }, ], customDashboardButtons: [ { tooltip: 'Reset state', icon: { name: 'refresh', }, buttonStyle: { tone: 'error', }, onClick: (_button, context) => { context.adaptableApi.stateApi.reloadInitialState(); }, }, ], }, initialState: { Dashboard: { Tabs: [ { Name: 'Default', Toolbars: ['Layout', 'PersistState'], }, ], }, Theme: {CurrentTheme: 'dark'}, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-github_stars', Rule: { Predicates: [ { PredicateId: 'GreaterThan', Inputs: [1000], }, ], }, Style: { BackColor: 'Yellow', ForeColor: 'Black', }, Scope: { ColumnIds: ['github_stars'], }, }, ], }, Layout: { CurrentLayout: 'Protected Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', 'has_wiki', 'pushed_at', 'open_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], }, { Name: 'Protected Layout', Tags: [PROTECTED_LAYOUT_TAG], RowGroupedColumns: ['language'], TableColumns: [ 'name', 'github_stars', 'github_watchers', 'updated_at', 'description', 'created_at', 'has_wiki', 'pushed_at', 'open_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], RowGroupValues: { RowGroupDefaultBehavior: 'collapsed', }, }, ], }, }, }; ``` ```ts import { AdaptableApi, AdaptablePersistentState, AdaptableStateFunctionConfig, StateOptions, Layout, } from '@adaptabletools/adaptable'; import {diffString} from 'json-diff'; let LAST_PERSISTED_STATE = {} as AdaptablePersistentState; export const PROTECTED_LAYOUT_TAG = 'Protected'; export const customStateOptions: StateOptions = { saveState: (state, adaptableStateFunctionConfig) => { const {adaptableApi} = adaptableStateFunctionConfig; const forcePersistState = shouldPersistState(adaptableApi); // if we are forcing the persist state, we want to save all changes // including the protected Layout if (forcePersistState) { cleanupPostPersistState(adaptableApi); return state; } // otherwise, keep the changes on the protected Layout local only and send the latest persisted state instead state.Layout.Layouts = state.Layout.Layouts.map(layout => { // for the protected layout, we want to return the last persisted state if (layout.Tags?.includes(PROTECTED_LAYOUT_TAG)) { const lastPersistedLayoutState = LAST_PERSISTED_STATE.Layout?.Layouts.find( persistedLayout => persistedLayout.Name === layout.Name ); if (!lastPersistedLayoutState) { console.error(`No persisted state found for layout ${layout.Name}`); return layout; } const layoutDiff = diffString(lastPersistedLayoutState, layout); if (layoutDiff.trim() !== '') { console.log(`Suppressing protected state persistence:`); console.log(layoutDiff); } return lastPersistedLayoutState; } // for all other layouts, we want to save the current state return layout; }) as [Layout, ...Layout[]]; return state; }, persistState: (state, adaptableStateFunctionConfig) => { const {adaptableStateKey} = adaptableStateFunctionConfig; console.log(`Persisting state!`); localStorage.setItem(adaptableStateKey, JSON.stringify(state)); updateLastPersistedState(state); return Promise.resolve(true); }, loadState: (config: AdaptableStateFunctionConfig) => { return new Promise(resolve => { let state = {} as AdaptablePersistentState; try { state = JSON.parse( localStorage.getItem(config.adaptableStateKey) as string ) || {}; } catch (err) { console.log('Error loading state', err); } updateLastPersistedState(state); resolve(state); }); }, }; type CustomStateSaveContext = { FORCE_PERSIST?: boolean; }; export function updateLastPersistedState(state: AdaptablePersistentState) { LAST_PERSISTED_STATE = state; } export function getStateDelta(adaptableState: AdaptablePersistentState) { const lastPersistedState = LAST_PERSISTED_STATE || {}; const changedState = adaptableState; const delta = diffString(lastPersistedState, changedState); return delta; } export function shouldPersistState(adaptableApi: AdaptableApi): boolean { return ( adaptableApi.optionsApi.getAdaptableContext() .FORCE_PERSIST === true ); } export function forcePersistState(adaptableApi: AdaptableApi) { adaptableApi.optionsApi.addToAdaptableContext( 'FORCE_PERSIST', true ); } export function cleanupPostPersistState(adaptableApi: AdaptableApi) { adaptableApi.optionsApi.addToAdaptableContext( 'FORCE_PERSIST', false ); adaptableApi.dashboardApi.refreshDashboard(); } ``` --- # Suspending Adaptable Objects Canonical page: https://www.adaptabletools.com/docs/dev-guide-adaptable-state-suspending - To Do Many objects in AdapTable derive from [`SuspendableObject`](https://www.adaptabletools.com/docs/reference/suspendableobject.md) (which itself derives from the `AdaptableObject`). Not all AdapTable Objects can be suspended as for some it makes no sense, e.g. [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) or [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) The interface exposes just a single, `IsSuspended`, property: | Property | Type | Description | | --- | --- | --- | | [IsSuspended](https://www.adaptabletools.com/docs/reference/suspendableobject.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/suspendableobject.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | When this property is set to to true, the object becomes inactive but remains in [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md). Suspendable Objects display a toggle button in the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md), enabling the object to be easily suspended - All [API classes](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) that deal with Suspendable Objects have **suspend** and **unSuspend** methods - For instance, `suspendCustomSort` and `unSuspendCustomSort` in [Custom Sort API](https://www.adaptabletools.com/docs/handbook-custom-sorting-technical-reference/index.md) --- # Adaptable State Technical Reference Canonical page: https://www.adaptabletools.com/docs/dev-guide-adaptable-state-technical-reference - State API is designed to help support to manage AdapTable State at run-time ## State Options | Property | Type | Description | Default | | --- | --- | --- | --- | | [applyState](https://www.adaptabletools.com/docs/reference/stateoptions.md#applystate) | `AdaptableApplyStateFunction` | Transforms state before applying it to the application. Called after `loadState()` but before the state is used. | | | [autoMigrateState](https://www.adaptabletools.com/docs/reference/stateoptions.md#automigratestate) | `boolean` | Automatically migrate State from previous AdapTable version to current one | true | | [clearState](https://www.adaptabletools.com/docs/reference/stateoptions.md#clearstate) | [`AdaptableClearStateFunction`](https://www.adaptabletools.com/docs/reference/adaptableclearstatefunction.md) | Allows clearing of remote Adaptable State. Only invoked during `StateApi.reloadInitialState()` operations. | undefined | | [debounceStateDelay](https://www.adaptabletools.com/docs/reference/stateoptions.md#debouncestatedelay) | `number` | Delay (in ms) to debounce `saveState` / `persistState` calls enabling grouping multiple sequential calls in single one (e.g. elevator doors) | 400 | | [loadState](https://www.adaptabletools.com/docs/reference/stateoptions.md#loadstate) | [`AdaptableLoadStateFunction`](https://www.adaptabletools.com/docs/reference/adaptableloadstatefunction.md) | Retrieves saved Adaptable State from storage or external source | | | [persistState](https://www.adaptabletools.com/docs/reference/stateoptions.md#persiststate) | [`AdaptablePersistStateFunction`](https://www.adaptabletools.com/docs/reference/adaptablepersiststatefunction.md) | Handles the actual storage of state to localStorage, server, etc. Called after `saveState()` to store the prepared state. | | | [saveState](https://www.adaptabletools.com/docs/reference/stateoptions.md#savestate) | [`AdaptableSaveStateFunction`](https://www.adaptabletools.com/docs/reference/adaptablesavestatefunction.md) | Transforms state before saving to storage. Called before `persistState()`. | | --- ## State API The [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) provides an easy way to access all Adaptable State at runtime. Nearly every class includes functions to allow developers to retrieve particular, relevant, portions of the State. But the State API class is particularly useful, containing many functions to manage access to AdapTable State: | Method | Returns | Description | | --- | --- | --- | | [copyAllStateToClipboard()](https://www.adaptabletools.com/docs/reference/stateapi.md#copyallstatetoclipboard) | `void` | Copies all Adaptable state to clipboard | | [copyUserStateToClipboard()](https://www.adaptabletools.com/docs/reference/stateapi.md#copyuserstatetoclipboard) | `void` | Copies User State sections of Adaptable State to clipboard | | [dispatchStateReadyAction(module)](https://www.adaptabletools.com/docs/reference/stateapi.md#dispatchstatereadyaction) | `void` | Sent by each Module when it is Ready | | [getAdaptableFilterState()](https://www.adaptabletools.com/docs/reference/stateapi.md#getadaptablefilterstate) | [`AdaptableFilterState`](https://www.adaptabletools.com/docs/reference/adaptablefilterstate.md) | Gets filter-related sections of Adaptable State | | [getAdaptableSortState()](https://www.adaptabletools.com/docs/reference/stateapi.md#getadaptablesortstate) | [`AdaptableSortState`](https://www.adaptabletools.com/docs/reference/adaptablesortstate.md) | Gets sort-related sections of Adaptable State | | [getAlertState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getalertstate) | [`AlertState`](https://www.adaptabletools.com/docs/reference/alertstate.md) | Returns Alert section of Adaptable State | | [getAllState()](https://www.adaptabletools.com/docs/reference/stateapi.md#getallstate) | [`AdaptableState`](https://www.adaptabletools.com/docs/reference/adaptablestate.md) | Retrieves ALL state which is currently stored by Adaptable (both persistent and transient/internal) | | [getApplicationState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getapplicationstate) | [`ApplicationState`](https://www.adaptabletools.com/docs/reference/applicationstate.md) | Returns Application section of Adaptable State | | [getCalculatedColumnState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getcalculatedcolumnstate) | [`CalculatedColumnState`](https://www.adaptabletools.com/docs/reference/calculatedcolumnstate.md) | Returns Calculated Column section of Adaptable State | | [getChartingState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getchartingstate) | [`ChartingState`](https://www.adaptabletools.com/docs/reference/chartingstate.md) | Returns Charting section of Adaptable State | | [getCustomSortState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getcustomsortstate) | [`CustomSortState`](https://www.adaptabletools.com/docs/reference/customsortstate.md) | Returns Custom Sort section of Adaptable State | | [getDashboardState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getdashboardstate) | [`DashboardState`](https://www.adaptabletools.com/docs/reference/dashboardstate.md) | Returns Dashboard section of Adaptable State | | [getDescriptionForModule(adaptableModule)](https://www.adaptabletools.com/docs/reference/stateapi.md#getdescriptionformodule) | `string` | Retrieves a brief description of an AdapTable Module | | [getExportState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getexportstate) | [`ExportState`](https://www.adaptabletools.com/docs/reference/exportstate.md) | Returns Export section of Adaptable State | | [getFlashingCellState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getflashingcellstate) | [`FlashingCellState`](https://www.adaptabletools.com/docs/reference/flashingcellstate.md) | Returns Flashing Cell section of Adaptable State | | [getFormatColumnState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getformatcolumnstate) | [`FormatColumnState`](https://www.adaptabletools.com/docs/reference/formatcolumnstate.md) | Returns Format Column section of Adaptable State | | [getFreeTextColumnState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getfreetextcolumnstate) | [`FreeTextColumnState`](https://www.adaptabletools.com/docs/reference/freetextcolumnstate.md) | Returns FreeText Column section of Adaptable State | | [getHelpPageForModule(adaptableModule)](https://www.adaptabletools.com/docs/reference/stateapi.md#gethelppageformodule) | `string` | Retrieves the help page for an AdapTable Module | | [getInitialState()](https://www.adaptabletools.com/docs/reference/stateapi.md#getinitialstate) | [`InitialState`](https://www.adaptabletools.com/docs/reference/initialstate.md)` \| any` | Returns the Initial Adaptable State | | [getLayoutState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getlayoutstate) | [`LayoutState`](https://www.adaptabletools.com/docs/reference/layoutstate.md) | Returns Layout section of Adaptable State | | [getNamedQueryState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getnamedquerystate) | [`NamedQueryState`](https://www.adaptabletools.com/docs/reference/namedquerystate.md) | Returns Query section of Adaptable State | | [getNoteState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getnotestate) | [`NoteState`](https://www.adaptabletools.com/docs/reference/notestate.md) | Returns Note section of Adaptable State | | [getPersistentState()](https://www.adaptabletools.com/docs/reference/stateapi.md#getpersistentstate) | [`AdaptablePersistentState`](https://www.adaptabletools.com/docs/reference/adaptablepersistentstate.md) | Retrieves the persistent state in Adaptable, i.e. state that is passed to the `StateOptions.persistState()` function. | | [getPlusMinusState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getplusminusstate) | [`PlusMinusState`](https://www.adaptabletools.com/docs/reference/plusminusstate.md) | Returns Plus Minus section of Adaptable State | | [getQuickSearchState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getquicksearchstate) | [`QuickSearchState`](https://www.adaptabletools.com/docs/reference/quicksearchstate.md) | Returns Quick Search section of Adaptable State | | [getShortcutState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getshortcutstate) | [`ShortcutState`](https://www.adaptabletools.com/docs/reference/shortcutstate.md) | Returns Shortcut section of Adaptable State | | [getStatusBarState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getstatusbarstate) | [`StatusBarState`](https://www.adaptabletools.com/docs/reference/statusbarstate.md) | Returns StatusBar section of Adaptable State | | [getStyledColumnState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getstyledcolumnstate) | [`StyledColumnState`](https://www.adaptabletools.com/docs/reference/styledcolumnstate.md) | Returns StyledColumn section of Adaptable State | | [getThemeState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getthemestate) | [`ThemeState`](https://www.adaptabletools.com/docs/reference/themestate.md) | Returns Theme section of Adaptable State | | [getToolPanelState(returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#gettoolpanelstate) | [`ToolPanelState`](https://www.adaptabletools.com/docs/reference/toolpanelstate.md) | Returns Tool Panel section of Adaptable State | | [getUserStateByStateKey(stateKey, returnJson)](https://www.adaptabletools.com/docs/reference/stateapi.md#getuserstatebystatekey) | [`BaseState`](https://www.adaptabletools.com/docs/reference/basestate.md)` \| string` | Returns given section of Adaptable State (as JSON or object) | | [incrementUserStateRevision(stateKey)](https://www.adaptabletools.com/docs/reference/stateapi.md#incrementuserstaterevision) | `void` | Adds '1' to current revision number of State element | | [loadUserState(state)](https://www.adaptabletools.com/docs/reference/stateapi.md#loaduserstate) | `void` | Loads supplied user state, replacing (NOT merging) existing User(persisted) State. | | [persistAdaptableState()](https://www.adaptabletools.com/docs/reference/stateapi.md#persistadaptablestate) | `Promise<`[`AdaptableState`](https://www.adaptabletools.com/docs/reference/adaptablestate.md)`>` | Persists the current Adaptable State to storage. | | [reloadInitialState(newInitialState)](https://www.adaptabletools.com/docs/reference/stateapi.md#reloadinitialstate) | `Promise` | Reloads existing (or supplied) Initial State; clears persistent state by calling `StateOptions.clearState` | | [setAdaptableStateKey(adaptableStateKey, config)](https://www.adaptabletools.com/docs/reference/stateapi.md#setadaptablestatekey) | `Promise` | Changes key used for persisting AdaptableState into localStorage; optionally provides an initialState to load | --- ## Initial State Inital State is the Adaptable State provided at design time for **first-time** use. The full definition of the object is: | Property | Type | Description | | --- | --- | --- | | [Alert](https://www.adaptabletools.com/docs/reference/initialstate.md#alert) | [`AlertState`](https://www.adaptabletools.com/docs/reference/alertstate.md) | Collection of `AlertDefinitions` which will fire Alerts when the rule is met | | [Application](https://www.adaptabletools.com/docs/reference/initialstate.md#application) | [`ApplicationState`](https://www.adaptabletools.com/docs/reference/applicationstate.md) | Empty state section (only populated at Design Time) available for User to store their own data with the rest of AdapTable state. | | [CalculatedColumn](https://www.adaptabletools.com/docs/reference/initialstate.md#calculatedcolumn) | [`CalculatedColumnState`](https://www.adaptabletools.com/docs/reference/calculatedcolumnstate.md) | Collection of *CalculatedColumn* objects that will display a value based on other cells in the row (using a Calculated Column Expression) | | [Charting](https://www.adaptabletools.com/docs/reference/initialstate.md#charting) | [`ChartingState`](https://www.adaptabletools.com/docs/reference/chartingstate.md) | Named Charts (wrapping Chart models) | | [CustomSort](https://www.adaptabletools.com/docs/reference/initialstate.md#customsort) | [`CustomSortState`](https://www.adaptabletools.com/docs/reference/customsortstate.md) | Collection of *Custom Sort* objects to allow some columns to be sorted in non-standard (e.g. non alphabetical) ways | | [Dashboard](https://www.adaptabletools.com/docs/reference/initialstate.md#dashboard) | [`DashboardState`](https://www.adaptabletools.com/docs/reference/dashboardstate.md) | Large series of properties to give users full control over the look and feel of the *Dashboard* - the section above the grid with toolbars and buttons | | [Export](https://www.adaptabletools.com/docs/reference/initialstate.md#export) | [`ExportState`](https://www.adaptabletools.com/docs/reference/exportstate.md) | Collection of *Report* objects, together with name of the Current Report, as part of AdapTable export Module | | [FlashingCell](https://www.adaptabletools.com/docs/reference/initialstate.md#flashingcell) | [`FlashingCellState`](https://www.adaptabletools.com/docs/reference/flashingcellstate.md) | Definitions of which cells flash in response to data changes | | [FormatColumn](https://www.adaptabletools.com/docs/reference/initialstate.md#formatcolumn) | [`FormatColumnState`](https://www.adaptabletools.com/docs/reference/formatcolumnstate.md) | Collection of *FormatColumn* objects that will style an entire column either fully or using a Condition | | [FreeTextColumn](https://www.adaptabletools.com/docs/reference/initialstate.md#freetextcolumn) | [`FreeTextColumnState`](https://www.adaptabletools.com/docs/reference/freetextcolumnstate.md) | Collection of *FreeText* objects so users can make their own notes in bespoke columns that will get stored with their state (and not with the DataSource). Useful if needing a 'Comments' column. | | [Layout](https://www.adaptabletools.com/docs/reference/initialstate.md#layout) | [`LayoutState`](https://www.adaptabletools.com/docs/reference/layoutstate.md) | Collection of *Layouts* to name (and manage) sets of column visibility, order, grouping, sorts, aggregations, filters etc. | | [NamedQuery](https://www.adaptabletools.com/docs/reference/initialstate.md#namedquery) | [`NamedQueryState`](https://www.adaptabletools.com/docs/reference/namedquerystate.md) | Named Queries available for use across multiple AdapTable Modules | | [Note](https://www.adaptabletools.com/docs/reference/initialstate.md#note) | [`NoteState`](https://www.adaptabletools.com/docs/reference/notestate.md) | Collection of personal Notes that are edited at Cell level | | [PlusMinus](https://www.adaptabletools.com/docs/reference/initialstate.md#plusminus) | [`PlusMinusState`](https://www.adaptabletools.com/docs/reference/plusminusstate.md) | Plus Minus module: nudge rules. Optional `IncrementKey` / `DecrementKey` on each nudge accept either a single key or a keyboard shortcut combination (e.g. `shift+Enter`); when omitted, `AdaptableOptions.plusMinusOptions` applies, then `+` / `-`. | | [QuickSearch](https://www.adaptabletools.com/docs/reference/initialstate.md#quicksearch) | [`QuickSearchState`](https://www.adaptabletools.com/docs/reference/quicksearchstate.md) | Configues how Quick Search will run i.e. how and whether to highlight matching cells and to filter out non-matching rows | | [Shortcut](https://www.adaptabletools.com/docs/reference/initialstate.md#shortcut) | [`ShortcutState`](https://www.adaptabletools.com/docs/reference/shortcutstate.md) | Collection of *Shortcut* objects to aid data entry and prevent 'fat finger' issues | | [StatusBar](https://www.adaptabletools.com/docs/reference/initialstate.md#statusbar) | [`StatusBarState`](https://www.adaptabletools.com/docs/reference/statusbarstate.md) | Configures the Adaptable Status Bar | | [StyledColumn](https://www.adaptabletools.com/docs/reference/initialstate.md#styledcolumn) | [`StyledColumnState`](https://www.adaptabletools.com/docs/reference/styledcolumnstate.md) | Collection of Special Column Styles | | [Theme](https://www.adaptabletools.com/docs/reference/initialstate.md#theme) | [`ThemeState`](https://www.adaptabletools.com/docs/reference/themestate.md) | Specifies current Theme and lists User and System themes available for selection | | [ToolPanel](https://www.adaptabletools.com/docs/reference/initialstate.md#toolpanel) | [`ToolPanelState`](https://www.adaptabletools.com/docs/reference/toolpanelstate.md) | Sets order & visibility of Tool Panel controls in AdapTable ToolPanel (on right of grid) | | [UserInterface](https://www.adaptabletools.com/docs/reference/initialstate.md#userinterface) | [`UserInterfaceState`](https://www.adaptabletools.com/docs/reference/userinterfacestate.md) | Controls the visibility of AdapTable UI elements (Dashboard, Tool Panel, Status Bar, Menus etc.) | Every item in the object, inherits from [`BaseState`](https://www.adaptabletools.com/docs/reference/basestate.md) which contains just one property: | Property | Type | Description | | --- | --- | --- | | [Revision](https://www.adaptabletools.com/docs/reference/basestate.md#revision) | `number \| \{ Key: number; UpdateStrategy: 'Override' \| 'KeepUserDefined'; \}` | Version number of the Item - allows developers to update one section in Initial Adaptable State while keeping others unchanged | --- ## AdapTable State Events AdapTable provides 3 State-related Events: - `BeforeAdaptableStateChanges` - fired before something changes in AdapTable State - `AdaptableStateChanged` - fired after anything changes in AdapTable State - `AdaptableStateReloaded` - fired whenever the State reloads See [Listening to Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-events/index.md) for full details ### Adaptable State Changed The full definition of the [`AdaptableStateChangedInfo`](https://www.adaptabletools.com/docs/reference/adaptablestatechangedinfo.md) object is: | Property | Type | Description | | --- | --- | --- | | [action](https://www.adaptabletools.com/docs/reference/adaptablestatechangedinfo.md#action) | `Redux.Action` | The Redux Action that was invoked | | [actionName](https://www.adaptabletools.com/docs/reference/adaptablestatechangedinfo.md#actionname) | `string` | Name of the Action | | [newState](https://www.adaptabletools.com/docs/reference/adaptablestatechangedinfo.md#newstate) | [`AdaptableState`](https://www.adaptabletools.com/docs/reference/adaptablestate.md) | Adaptable State after the Action | | [oldState](https://www.adaptabletools.com/docs/reference/adaptablestatechangedinfo.md#oldstate) | [`AdaptableState`](https://www.adaptabletools.com/docs/reference/adaptablestate.md) | Adaptable State before the Action | | [adaptableContext](https://www.adaptabletools.com/docs/reference/adaptablestatechangedinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ### Before Adaptable State Changes The full definition of the [`BeforeAdaptableStateChangeInfo`](https://www.adaptabletools.com/docs/reference/beforeadaptablestatechangeinfo.md) object is: | Property | Type | Description | | --- | --- | --- | | [action](https://www.adaptabletools.com/docs/reference/beforeadaptablestatechangeinfo.md#action) | `Redux.Action` | The Redux Action that is about to be invoked | | [actionName](https://www.adaptabletools.com/docs/reference/beforeadaptablestatechangeinfo.md#actionname) | `string` | Name of the Action about to be performed | | [state](https://www.adaptabletools.com/docs/reference/beforeadaptablestatechangeinfo.md#state) | [`AdaptableState`](https://www.adaptabletools.com/docs/reference/adaptablestate.md) | Current Adaptable State (before the Action is applied) | | [adaptableContext](https://www.adaptabletools.com/docs/reference/beforeadaptablestatechangeinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ### Adaptable State Reloaded The full definition of the [`AdaptableStateReloadedInfo`](https://www.adaptabletools.com/docs/reference/adaptablestatereloadedinfo.md) object is: | Property | Type | Description | | --- | --- | --- | | [newState](https://www.adaptabletools.com/docs/reference/adaptablestatereloadedinfo.md#newstate) | [`AdaptablePersistentState`](https://www.adaptabletools.com/docs/reference/adaptablepersistentstate.md) | Adaptable State after the reload | | [oldState](https://www.adaptabletools.com/docs/reference/adaptablestatereloadedinfo.md#oldstate) | [`AdaptablePersistentState`](https://www.adaptabletools.com/docs/reference/adaptablepersistentstate.md) | Adaptable State before the reload | | [adaptableContext](https://www.adaptabletools.com/docs/reference/adaptablestatereloadedinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ### Base Event Info Both EventInfo objects from [`BaseContext`](https://www.adaptabletools.com/docs/reference/basecontext.md) defined as follow: | 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 Events is done the same as with all [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md): ```ts api.eventApi.on( 'AdaptableStateChanged', (eventInfo: AdaptableStateChangedInfo) => { // do something with the info } ); api.eventApi.on( 'AdaptableStateReloaded', (eventInfo: AdaptableStateReloadedInfo) => { // do something with the info } ); ``` --- # Creating Array Columns Canonical page: https://www.adaptabletools.com/docs/dev-guide-aggrid-array-columns - Array Columns contain multiple values in each Cell - AdapTable supports these and enables rendering in Badge Styles or Sparkline Columns - Calculated Columns which contain arrays can also be created - Filtering is available in Array Columns using the In Filter AG Grid provides [Cell Data Types](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) which AdapTable leverages to know the data type of a Column. This allows AdapTable to create the correct Filters and Menus For the majority of Columns, these cell data types are all that is needed. However, there are a few use cases - all regarding array data - where the the AG Grid types are insufficient. In these scenarios, one of these array values provided by AdapTable should be used instead: - `textArray` - `numberArray` - `tupleArray` - `objectArray` ## Sparkline Columns If defining a Column that will use a [Sparkline Column Style](https://www.adaptabletools.com/docs/handbook-styled-column-sparkline/index.md) then a numeric array is required. AdapTable provides 3 types of numeric arrays: | Type of Data | Value for `cellDataType` property | Example | | ------------------------ | --------------------------------- | ---------------------------------------------------- | | Numeric Array | `numberArray` | `[27, 5, 13, 25]` | | Array of Numeric Tuples | `tupleArray` | `[ [14, 22], [5, 13], [19, 30] ]` | | Array of Numeric Objects | `objectArray` | `[ \{x: 14, y: 22\}, \{x: 5, y: 13\}, \{x: 19, y: 30\} ]` | ```tsx {6,11} const gridOptions: GridOptions = { columnDefs: [ { headerName: 'History', field: 'history', cellDataType: 'numberArray', }, { headerName: 'Prices', field: 'prices', cellDataType: 'tupleArray', }, ], }; ``` ## Badge Styles A common use case when creating a [Badge Style](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md#arrays) is to show a distinct badge for each separate item in a cell. Again, the way to achieve this is to use an AdapTable-provided value for the cellDataType. | Type of Data | Value for `cellDataType` property | Example | | ------------ | --------------------------------- | --------------------------------------- | | String Array | `textArray` (or `numberArray`) | ['US', 'GBP', 'France'] (or [19,11,27]) | It is also possible to use the `numberArray` cell data type in Array Badge Styles ```tsx {6} const gridOptions: GridOptions = { columnDefs: [ { headerName: 'Institutions', field: 'institutions', cellDataType: 'textArray', }, ], }; ``` ## Calculated Columns It is possible to create [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) which will display Array data. Typically the Calculated Column's Expresssion will include the `TO_ARRAY` [Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) to create the array. - When defining the Calculated Column, an appropriate array cell data type should be used (e.g. numeric or string) - If using the Calculated Column UI Wizard, AdapTable works out the appropriate cell data type from the Expression You can create a Sparkline Column to render the Calculated Column's array if required ## Filtering AdapTable fully supports Column Filtering in Array based columns. The [In Filter](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md) is used as the default Predicate, and any row which contains a selected value is displayed. **Example: Array Cell Data Type** Using Array Columns - This demo contains 2 array-based Columns: - `Institutions` column (`textArray`) - we created 7 Badges each with a Rule (per institution), and a (Green) Badge for institutions which do not meet any Predicate - `Ratings` column (`numericArray`) - shows a Sparkline Column - note this column is a Calculated Column where the array is the output of a `TO_ARRAY` [Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) - Filter the `Institutions` Column so that just rows containing Princeton or Columnbia are visible ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'EmployeeId', adaptableId: 'Array Cell Data Type', initialState: { Dashboard: { ModuleButtons: ['StyledColumn', 'CalculatedColumn', 'SettingsPanel'], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Basic Layout', Layouts: [ { Name: 'Basic Layout', TableColumns: [ 'Name', 'Year', 'Country', 'CountryCode', 'Institutions', 'Email', 'Ratings', 'Rating2025', 'Rating2024', 'Rating2023', 'Rating2022', 'Rating2021', ], ColumnSizing: { Name: {Width: 130}, Year: {Width: 80}, Country: {Width: 150}, CountryCode: {Width: 120}, Institutions: {Width: 300}, Email: {Width: 150}, Ratings: {Width: 300}, Rating2025: {Width: 100}, Rating2024: {Width: 100}, Rating2023: {Width: 100}, Rating2022: {Width: 100}, Rating2021: {Width: 100}, }, }, ], }, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'Ratings', FriendlyName: 'Ratings', Query: { ScalarExpression: 'TO_ARRAY([Rating2025], [Rating2024], [Rating2023], [Rating2022], [Rating2021])', }, CalculatedColumnSettings: { Resizable: true, DataType: 'numberArray', }, }, ], }, StyledColumn: { StyledColumns: [ { Name: 'Institutions Badge', ColumnId: 'Institutions', BadgeStyle: { Badges: [ { PillStyle: { BackColor: 'LightGreen', ForeColor: 'Black', }, Predicate: { PredicateId: 'Is', Inputs: ['Columbia'], }, }, { PillStyle: { BackColor: 'Purple', ForeColor: 'White', }, Predicate: { PredicateId: 'Is', Inputs: ['Princeton'], }, }, { PillStyle: { BackColor: 'Brown', ForeColor: 'White', }, Predicate: { PredicateId: 'Is', Inputs: ['Max Planck'], }, }, { PillStyle: { BackColor: 'Orange', ForeColor: 'Black', }, Predicate: { PredicateId: 'Is', Inputs: ['Geneva'], }, }, { PillStyle: { BackColor: 'LightBlue', ForeColor: 'Black', }, Predicate: { PredicateId: 'Is', Inputs: ['University of Cambridge'], }, }, { PillStyle: { BackColor: 'DarkBlue', ForeColor: 'White', }, Predicate: { PredicateId: 'Is', Inputs: ['Oxford University'], }, }, { PillStyle: { BackColor: 'Pink', ForeColor: 'Black', }, Predicate: { PredicateId: 'Is', Inputs: ['Hamburg'], }, }, { PillStyle: { BackColor: 'DarkGreen', ForeColor: 'White', }, }, ], }, }, { Name: 'Ratings Sparkline', ColumnId: 'Ratings', SparklineStyle: { options: { type: 'bar', direction: 'horizontal', fill: '#5470c6', stroke: '#91cc75', }, }, }, ], }, }, }; ``` ```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: '2025 Rating', field: 'Rating2025', filter: true, editable: true, sortable: true, cellDataType: 'number', }, { headerName: '2024 Rating', field: 'Rating2024', filter: true, editable: true, sortable: true, cellDataType: 'number', }, { headerName: '2023 Rating', field: 'Rating2023', filter: true, editable: true, sortable: true, cellDataType: 'number', }, { headerName: '2022 Rating', field: 'Rating2022', filter: true, editable: true, sortable: true, cellDataType: 'number', }, { headerName: '2021 Rating', field: 'Rating2021', filter: true, editable: true, sortable: true, cellDataType: 'number', }, ]; ``` ```ts export const rowData = [ { EmployeeId: 1, Name: 'Giorgio Parisi', Year: 2021, Institutions: ['Sapienza', 'Columbia'], Country: 'Italy', CountryCode: 'ITA', Email: 'giorgio.parisi@mail.com', Rating2025: 4, Rating2024: 7, Rating2023: 5, Rating2022: 8, Rating2021: 8, }, { EmployeeId: 2, Name: 'Klaus Hasselman', Year: 2021, Institutions: ['Hamburg', 'Max Planck'], Country: 'Germany', CountryCode: 'DEU', Email: 'klaus.hasselman@yahoo.com', Rating2025: 5, Rating2024: 3, Rating2023: 7, Rating2022: 7, Rating2021: 4, }, { EmployeeId: 3, Name: 'Syukor Manabe', Year: 2021, Institutions: ['Princeton', 'Nagoya'], Country: 'Japan', CountryCode: 'JPN', Email: 'syukor.manabe@outlook.com', Rating2025: 6, Rating2024: 7, Rating2023: 6, Rating2022: 8, Rating2021: 6, }, { EmployeeId: 4, Name: 'Andrea Ghez', Year: 2020, Institutions: ['University of Cambridge'], Country: 'United States', CountryCode: 'USA', Email: 'andrea.ghez@mail.com', Rating2025: 10, Rating2024: 7, Rating2023: 8, Rating2022: 8, Rating2021: 6, }, { EmployeeId: 5, Name: 'Reinhard Genzel', Year: 2020, Institutions: ['Max Planck', 'Oxford University'], Country: 'Germany', CountryCode: 'DEU', Email: 'reinhard.genzel@mail.com', Rating2025: 9, Rating2024: 5, Rating2023: 8, Rating2022: 7, Rating2021: 8, }, { EmployeeId: 6, Name: 'Roger Penrose', Year: 2020, Institutions: ['Columbia', 'Princeton', 'Syracuse'], Country: 'United Kingdom', CountryCode: 'GBR', Email: 'roger.penrose@yahoo.com', Rating2025: 8, Rating2024: 10, Rating2023: 10, Rating2022: 8, Rating2021: 9, }, { EmployeeId: 7, Name: 'Didier Queloz', Year: 2019, Institutions: ['University of Cambridge', 'Geneva'], Country: 'Switzerland', CountryCode: 'CHE', Email: 'didier.queloz@mail.com', Rating2025: 7, Rating2024: 5, Rating2023: 6, Rating2022: 8, Rating2021: 6, }, { EmployeeId: 8, Name: 'Michel Mayor', Year: 2019, Institutions: ['Geneva', 'Columbia'], Country: 'Switzerland', CountryCode: 'CHE', Email: 'michel.mayor@yahoo.com', Rating2025: 9, Rating2024: 10, Rating2023: 9, Rating2022: 6, Rating2021: 8, }, { EmployeeId: 9, Name: 'Jim Peebles', Year: 2019, Institutions: ['Oxford University', 'Princeton'], Country: 'United States', CountryCode: 'USA', Email: 'jim.peebles@outlook.com', Rating2025: 7, Rating2024: 9, Rating2023: 10, Rating2022: 9, Rating2021: 8, }, ]; ``` --- # Setting AG Grid Cell Data Types Canonical page: https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types - Developers should provide the `cellDataType` property as part of each AG Grid Column definition - AdapTable will then set the **data types** of the columns, ensuring filters and menus are correctly configured AdapTable needs to know the correct data type of each Column in AG Grid. This will ensure that appropriate [Filter Predicates](https://www.adaptabletools.com/docs/handbook-column-filter/index.md), [Column Menus](https://www.adaptabletools.com/docs/ui-column-menu-technical-reference/index.md) etc. are configured correctly for the Column AdapTable does this by leveraging the `cellDataType` property that is part of each AG Grid `ColDef` object. - Prior to [AdapTable Version 20](https://www.adaptabletools.com/support/version-200-release-note) the `type` property of the Column Definition was used for this purpose - This was changed to leverage the more powerful `cellDataType` property introduced by AG Grid v.32 If this is not provided, AdapTable will attempt to work out the DataType of the column, by analysing the data in the first row of the Grid. Not providing Column Data Types can cause issues, particularly if the data in the first row is missing or ambiguous ## AG Grid Cell Data Types When setting up Column Definitions, developers should ensure to set the correct `cellDataType` property. For the vast majority of Columns, the default values provided by AG grid will suffice: | Column Data Type | AG Grid `cellDataType` value | Defunct AdapTable `type` value | | ---------------- | ---------------------------- | ------------------------------ | | String | `text` | `abColDefString` | | Numeric | `number` | `abColDefNumber` | | Date | `date` | `abColDefDate` | | Date (as string) | `dateString` | `abColDefDate` | | Boolean | `boolean` | `abColDefBoolean` | | Object | `object` | `abColDefObject` | ```tsx {6,11,16,21,27} const gridOptions: GridOptions = { columnDefs: [ { headerName: 'Make', field: 'make', cellDataType: 'text', // previously type: 'abColDefString' }, { headerName: 'Released', field: 'released', cellDataType: 'date', // previously type: 'abColDefDate' }, { headerName: 'Updated', field: 'updated', cellDataType: 'dateString', // previously type: 'abColDefDate' }, { headerName: 'Bid', field: 'bid', cellDataType: 'number',// previously type: 'abColDefNumber' type: 'pricing', // you can still use type prop to create column "sets" }, { headerName: 'Automatic', field: 'automaticTransmission', cellDataType: 'boolean', // previously type: 'abColDefBoolean' }, ], }; ``` **Example: AG Grid Cell Data Types** Using AG Grid Cell Data Types in AdapTable - This demo shows how AdapTable leverages AG Grid Cell Data Types using a (nonsensical) data set with these columns: - `Make` and `Model` are **text** - `Price` and `Rating` are **numbers** - `Available` is a **boolean** - `Made` is a **date** and `Produced` is a **dateString** - but both become AdapTable Dates (and therefore they share the same Format Column) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {Car} from './rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'model', adaptableId: 'AG Grid Cell Data Types', initialState: { Theme: {CurrentTheme: 'dark'}, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-date', Scope: { DataTypes: ['date'], }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'MMM do yyyy', }, }, Style: { ForeColor: 'LightBlue', }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'make', 'model', 'made', 'produced', 'available', 'pricePerMile', 'rating', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {GridOptions, themeBalham} from 'ag-grid-enterprise'; import {columnDefs} from './columnDefs'; import {rowData, Car} from './rowData'; 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 {ColDef} from 'ag-grid-enterprise'; import {Car} from './rowData'; export const columnDefs: ColDef[] = [ { headerName: 'Make', field: 'make', filter: true, editable: false, enableRowGroup: true, enablePivot: true, cellDataType: 'text', }, { headerName: 'Model', field: 'model', filter: true, editable: false, cellDataType: 'text', }, { headerName: 'Price', field: 'pricePerMile', filter: true, editable: false, cellDataType: 'number', }, { headerName: 'Made', field: 'made', filter: true, editable: false, cellDataType: 'date', }, { headerName: 'Produced', field: 'produced', filter: true, editable: false, cellDataType: 'dateString', }, { headerName: 'Available', field: 'available', filter: true, editable: true, cellDataType: 'boolean', }, { headerName: 'Rating', field: 'rating', enableValue: true, editable: true, sortable: true, cellDataType: 'number', filter: true, enablePivot: true, resizable: true, }, ]; ``` ```ts export interface Car { make: string; model: string; made: Date; produced: string; available: boolean; pricePerMile: number; rating: number; } export const rowData: Car[] = [ { make: 'Toyota', model: 'Celica', made: new Date(2017, 11, 4), produced: '4 December 2017', available: true, pricePerMile: 21.345676, rating: 1, }, { make: 'Toyota', model: 'Yaris', made: new Date(2013, 1, 15), produced: '15 February 2013', available: true, pricePerMile: 29.32432423, rating: 4, }, { make: 'Toyota', model: 'Corolla', made: new Date(2017, 6, 9), produced: '09-July-2017', available: false, pricePerMile: 32.9032523473287, rating: 5, }, { make: 'Ford', model: 'Mondeo', made: new Date(2009, 10, 2), produced: '2 November 2009', available: true, pricePerMile: 28.247893473289, rating: 4, }, { make: 'Ford', model: 'Fiesta', made: new Date(2018, 8, 12), produced: '12 September 2018', available: false, pricePerMile: 34.0001, rating: 5, }, { make: 'Ford', model: 'Focus', made: new Date(2017, 3, 3), produced: '03 April 2017', available: false, pricePerMile: 31.2432432423, rating: 3, }, { make: 'Ford', model: 'Galaxy', made: new Date(2015, 4, 14), produced: '14 May 2015', available: false, pricePerMile: 29.29432404, rating: 2, }, { make: 'Porsche', model: 'Boxter', made: new Date(2016, 1, 28), produced: '28 Feb 2016', available: true, pricePerMile: 32.29580292, rating: 4, }, { make: 'Porsche', model: 'Mission', made: new Date(2008, 10, 7), produced: '7 November 2008', available: false, pricePerMile: 35.7822957, rating: 5, }, { make: 'Mitsubbishi', model: 'Outlander', made: new Date(2017, 11, 14), produced: '14 December 2017', available: true, pricePerMile: 19.224309, rating: 4, }, ]; ``` ## Array Types There are a few use cases (all regarding array data) where the the AG Grid types are insufficient. In this case AdapTable provides a number of different array-based cell data types. See [creating Array Columns](https://www.adaptabletools.com/docs/dev-guide-aggrid-array-columns/index.md) for full details and accompanying demos --- # Using AG Grid Cell Rendering Canonical page: https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-rendering - AG Grid's Value Getters, Value Formatters and Cell Components are fully supported in AdapTable - Nevertheless we recommend using AdapTable Styling and Formatting wherever possible instead ## AG Grid Rendering Objects AG Grid provides very powerful functionality to enable custom cell and column content. This is primarily achieved using 2 objects (depending on the complexity of the use case): - [Value Formatters](https://www.ag-grid.com/javascript-data-grid/value-formatters/) - allow users to **format** the values which are displayed (essentially text formatting) - [Cell Components](https://www.ag-grid.com/javascript-data-grid/cell-rendering/) (previously called Cell Renderers) - allow users to **display anything** in a cell Both 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**, where possible. Instead we recommend using: - AdapTable's [Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md) in place of Value Formatters - AdapTable's [Styling](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md) and [Styled Columns](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md) in place of Cell Components Behind the scenes AdapTable will, itself, convert its objects to AG Grid Value Formatters and Cell Components This recommendation is made for a number of reasons, based on extensive user experience, including: - AdapTable's objects can be changed at run-time via Wizards - AdapTable's objects are fully saveable in State, and therefore shareable with colleagues - AdapTable will ensure that they always work if AG Grid's api changes (i.e. they are future-proofed) - Additionally, AG Grid supports [Value Getters](https://www.ag-grid.com/javascript-data-grid/value-getters/) which allow users to **retrieve** the cell value using custom logic - These can sometimes be replaced with [AdapTable Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) **Example: AG Grid Cell Rendering & Formatting** How AG Grid Column Components and Value Formatters work with AdapTable - This demo shows how AG Grid Column Components and Value Formatters works with AdapTable - We created a (nonsensical) data set which we render using a mixture of different AG Grid and AdapTable formatting and rendering options (often displaying same field twice) as follows: - `Made` appears twice, once with an [AG Grid Value Formattter](https://www.ag-grid.com/javascript-data-grid/value-formatters/) and once with an [AdapTable Date Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md) - `Price` appears twice, once with an [AG Grid Value Formattter](https://www.ag-grid.com/javascript-data-grid/value-formatters/) and once with an [AdapTable Numeric Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md) - `Rating` appears 3 times, once with an [AG Grid Value Formattter](https://www.ag-grid.com/javascript-data-grid/value-formatters/), once with an an [AG Grid Cell Component](https://www.ag-grid.com/javascript-data-grid/cell-rendering/) and once with an [AdapTable Custom Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-custom/index.md) - `Composite` appears twice, once with an [AG Grid Value Getter](https://www.ag-grid.com/javascript-data-grid/value-getters/) and once using an [AdapTable Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - `Model` has an [AdapTable (Badge) Styled Column](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md) configured in Initial Adaptable State - Export `Current Layout` to Excel and note how AdapTable can display the display values for columns using AG Grid's Value Formatter (but not if using a Cell Component) ```ts import { AdaptableOptions, CustomDisplayFormatterContext, } from '@adaptabletools/adaptable'; import {Car} from './rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'model', adaptableId: 'AG Grid Cell Rendering', formatColumnOptions: { customDisplayFormatters: [ { id: 'ratingFormat', label: 'Rating Format', scope: { DataTypes: ['number'], }, handler: ( customDisplayFormatterContext: CustomDisplayFormatterContext ) => { const cellValue: number = customDisplayFormatterContext.cellValue as number; return '*'.repeat(cellValue); }, }, ], }, initialState: { Dashboard: { PinnedToolbars: ['Export'], }, Export: { CurrentReport: 'Current Layout', CurrentFormat: 'VisualExcel', }, Theme: {CurrentTheme: 'dark'}, StyledColumn: { StyledColumns: [ { Name: 'model Badge', ColumnId: 'model', BadgeStyle: { Badges: [ { PillStyle: { BackColor: 'DarkGray', ForeColor: 'White', }, }, ], }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-price_adaptable', Scope: { ColumnIds: ['price_adaptable'], }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { FractionDigits: 2, Prefix: '$', }, }, }, { Name: 'formatColumn-made_adaptable', Scope: { ColumnIds: ['made_adaptable'], }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'dd/MM/yyyy', }, }, }, { Name: 'formatColumn-rating_df', Scope: { ColumnIds: ['rating_df'], }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { CustomDisplayFormats: ['ratingFormat'], }, }, }, ], }, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'composite_adaptable', FriendlyName: 'Composite (AdapTable)', CalculatedColumnSettings: { DataType: 'text', }, Query: { ScalarExpression: '[make] + " - " + [model] ', }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'make', 'model', 'made_aggrid', 'made_adaptable', 'price_aggrid', 'price_adaptable', 'rating_vf', 'rating_cc', 'rating_df', 'composite_aggrid', 'composite_adaptable', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {GridOptions, themeBalham} from 'ag-grid-enterprise'; import {columnDefs} from './columnDefs'; import {rowData, Car} from './rowData'; 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 {ColDef} from 'ag-grid-enterprise'; import {Car} from './rowData'; export const columnDefs: ColDef[] = [ { headerName: 'Make', field: 'make', filter: true, editable: false, enableRowGroup: true, enablePivot: true, cellDataType: 'text', }, { headerName: 'Model (SC)', field: 'model', filter: true, editable: false, cellDataType: 'text', }, { headerName: 'Price (VF)', field: 'pricePerMile', colId: 'price_aggrid', filter: true, editable: false, cellDataType: 'number', valueFormatter: (params: any) => { return params.value ? params.value.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, style: 'currency', currency: 'USD', }) : null; }, }, { headerName: 'Price (DF)', field: 'pricePerMile', colId: 'price_adaptable', filter: true, editable: false, cellDataType: 'number', }, { headerName: 'Made (VF)', field: 'made', colId: 'made_aggrid', filter: true, editable: false, cellDataType: 'date', valueFormatter: (params: any) => { return params.value ? new Intl.DateTimeFormat('en-GB').format(params.value) : ''; }, }, { headerName: 'Made (DF)', field: 'made', colId: 'made_adaptable', filter: true, editable: false, cellDataType: 'date', }, { headerName: 'Available', field: 'available', filter: true, editable: true, cellDataType: 'boolean', }, { headerName: 'Rating (VF)', field: 'rating', colId: 'rating_vf', enableValue: true, editable: true, sortable: true, valueFormatter: (params: any) => { let text = ''; for (var i = 0; i < params.value; i++) { text += '*'; } return text; }, cellDataType: 'number', filter: true, enablePivot: true, resizable: true, }, { headerName: 'Rating (CC)', field: 'rating', colId: 'rating_cc', enableValue: true, editable: true, sortable: true, cellRenderer: RatingRenderer, cellDataType: 'number', filter: true, enablePivot: true, resizable: true, }, { headerName: 'Rating (DF)', field: 'rating', colId: 'rating_df', enableValue: true, editable: true, sortable: true, cellDataType: 'number', filter: true, enablePivot: true, resizable: true, }, { headerName: 'Composite (AG)', editable: false, colId: 'composite_aggrid', filter: true, enableRowGroup: true, valueGetter: (params: any) => { return params.data && params.data.make && params.data.model ? params.data.make + ' - ' + params.data.model : undefined; }, cellDataType: 'text', }, ]; /* The Cell Render for Rating. We provide implementations for the init and getGui methods. */ function RatingRenderer() {} RatingRenderer.prototype.init = function (params: any): any { this.eGui = document.createElement('span'); var text = ''; for (var i = 0; i < params.value; i++) { text += '*'; } this.eGui.innerHTML = text; }; RatingRenderer.prototype.getGui = function (): any { return this.eGui; }; ``` ```ts export interface Car { make: string; model: string; made: Date; available: boolean; pricePerMile: number; rating: number; } export const rowData: Car[] = [ { make: 'Toyota', model: 'Celica', made: new Date(2017, 11, 4), available: true, pricePerMile: 21.345676, rating: 1, }, { make: 'Toyota', model: 'Yaris', made: new Date(2013, 1, 15), available: true, pricePerMile: 29.32432423, rating: 4, }, { make: 'Toyota', model: 'Corolla', made: new Date(2017, 6, 9), available: false, pricePerMile: 32.9032523473287, rating: 5, }, { make: 'Ford', model: 'Mondeo', made: new Date(2009, 10, 2), available: true, pricePerMile: 28.247893473289, rating: 4, }, { make: 'Ford', model: 'Fiesta', made: new Date(2018, 8, 12), available: false, pricePerMile: 34.0001, rating: 5, }, { make: 'Ford', model: 'Focus', made: new Date(2017, 3, 3), available: false, pricePerMile: 31.2432432423, rating: 3, }, { make: 'Ford', model: 'Galaxy', made: new Date(2015, 4, 14), available: false, pricePerMile: 29.29432404, rating: 2, }, { make: 'Porsche', model: 'Boxter', made: new Date(2016, 1, 28), available: true, pricePerMile: 32.29580292, rating: 4, }, { make: 'Porsche', model: 'Mission', made: new Date(2008, 10, 7), available: false, pricePerMile: 35.7822957, rating: 5, }, { make: 'Mitsubbishi', model: 'Outlander', made: new Date(2017, 11, 14), available: true, pricePerMile: 19.224309, rating: 4, }, ]; ``` --- # Configuring AG Grid ColDefs Canonical page: https://www.adaptabletools.com/docs/dev-guide-aggrid-columns There are many topics related to configuring AG Grid Columns, elsewhere in the documentation, primarily in the "Managing Columns" section. Relevant documentation pages include: - [Configuring AG Grid ColDefs at Design Time](https://www.adaptabletools.com/docs/dev-guide-columns-configuring-coldefs/index.md) - [Managing AG Grid ColDefs at RunTime](https://www.adaptabletools.com/docs/dev-guide-columns-managing-runtime/index.md) - [Setting Cell / Column Data Types in ColDefs](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) - [Providing AG Grid Column Types](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) --- # AdapTable Layouts and AG Grid GridOptions Canonical page: https://www.adaptabletools.com/docs/dev-guide-aggrid-configuring-gridoptions - Most AG Grid GridOptions properties will work just the same when AdapTable is being used - However there are some GridOptions properties which are **ignored** (in favoour of AdapTable alternatives) - And there are other properties which must be **provided**, for some AdapTable functionality to work The vast majority of properties in AG Grid's `GridOptions` object work as normal when using AdapTable. In other words, AdapTable has no opinions on whether or not they should be provided. However there are some GridOptions properties which are affected when using AdapTable. These properties can be divided into 2 groups: - **ignored** by AdapTable (as alternatives are provided in the [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md)) - **required** by AdapTable for some functionality ## Ignored Grid Options Props Some GridOptions properties will be ignored by AdapTable and their value will not be reflected in the Grid. - This most usually occurs when AdapTable provides the same functionality at a [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) level - Per-Layout configuration allows you to set different behaviour for different use cases The more important of these GridOptions properties are: | GridOptions property | AdapTable Layout Property | Notes | | ------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `grandTotalRow` | `GrandTotalRow` | Can be one of: `top` `bottom` `pinnedTop` `pinnedBottom` `boolean` | | `suppressAggFuncInHeader` | `SuppressAggFuncInHeader` | Allows this to be set on a per-Layout basis | | `rowSelection` | `RowSelection` | If provided in Layout or explicitly set to false, AG Grid prop ignored; but if Layout prop is undefined, we fall back to AG Grid value | ## Leveraged Grid Options Props Some functionality in AdapTable requires that relevant GridOptions properties be appropriately configured. This primarily occurs where AdapTable adds its own content into AG Grid's UI components. ### Status Bar To DO ### Tool Panel AdapTable adds its own [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) to the AG Grid **Sidebar**, providing access to core AdapTable functionality. In order to see the AdapTable Tool Panel, the GridOptions `sideBar` property must: - either be set to true ``` gridOptions.sideBar = true ``` - explicitly list it in the array, e.g. ``` gridOptions.sideBar = ['adaptable', 'filters'] ``` See [Configuring the Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel-configuring/index.md) for more information --- # Configuring AG Grid Canonical page: https://www.adaptabletools.com/docs/dev-guide-aggrid-configuring-overview - AdapTable extends AG Grid - which therefore still needs to be configured - This section examines some of the topics involved The topics in this section include: | Tutorial | | --------------------------------------------------------------------------------------------------------- | | [AdapTable and AG Grid Grid Options](https://www.adaptabletools.com/docs/dev-guide-aggrid-configuring-gridoptions/index.md) | | [Using AG Grid Cell Rendering](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-rendering/index.md) | | [Using AG Grid Pagination](https://www.adaptabletools.com/docs/dev-guide-aggrid-pagination/index.md) | Also see in other Pages: | Tutorial | | -------------------------------------------------------------------------------------- | | [Configuring AG Grid ColDefs at Design-Time](https://www.adaptabletools.com/docs/dev-guide-columns-configuring-coldefs/index.md) | | [Managing AG Grid ColDefs at Run-Time](https://www.adaptabletools.com/docs/dev-guide-columns-managing-runtime/index.md) | | [Providing AG Grid Modules](https://www.adaptabletools.com/docs/getting-started-aggrid-modules/index.md) | --- # AG Grid Pagination Canonical page: https://www.adaptabletools.com/docs/dev-guide-aggrid-pagination - AG Grid's Pagination works fully in AdapTable [AG Grid Pagination](https://www.ag-grid.com/javascript-data-grid/row-pagination/) is a very popular option for heavily populated Grids. It allows users to click between 'pages', rather than needing to scroll. Pagination is also fully supported by AdapTable and works fully as expected. - AdapTable does not provide any pagination-related features or options - If you would like to do something pagination-related in AG Grid but which is not possible, [please contact us](mailto:sales@adaptabletools.com) **Example: Using AG Grid Pagination** How AG Grid Pagination works in AdapTable - This demo shows Pagination with 10 rows per page - We have added a Column Filter on `Language` column so that initially there are 2 pages - Clear the filter on the `Language` column and note that there are now 3 pages - Switch to the Grouped Layout and note that only 1 page is required ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pagination', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout', 'Export', 'ColumnFilter']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout', 'Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Grouped Layout', RowGroupedColumns: ['language', 'license'], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'license', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', 'has_wiki', 'pushed_at', 'open_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], ColumnFilters: [ { ColumnId: 'language', Predicates: [ { PredicateId: 'Is', Inputs: ['JavaScript'], }, ], }, ], AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {GridOptions, themeBalham} from 'ag-grid-enterprise'; import {columnDefs} from 'columnDefs'; import {rowData} from 'rowData'; 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, pagination: true, paginationPageSize: 10, statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` --- # Adaptable Column Canonical page: https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column - AdapTable creates an `AdaptableColumn` object for every AG Grid Column each time the Application starts - AdapTable Columns are created from 3 sources: - Every column defined in `columnDefs` property of AG Grid GridOptions - Special Columns used in AdapTable - i.e. [Action](https://www.adaptabletools.com/docs/handbook-action-column/index.md), [Calculated](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) and [FreeText](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) Columns - Columns dynamically created by AG Grid (e.g. Row Grouped Columns, Pivot Columns, Tree Columns etc.) - Many objects in [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md) rely heavily on Columns and generally use the `columnId` property When AdapTable is being initialised it dynamically creates a collection of [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md) objects. There is one Adaptable Column for every column in the Grid, and they can be of 3 types: - Based on the `ColDef` provided in the `columnDefs` property of [GridOptions](https://www.ag-grid.com/javascript-data-grid/grid-interface/#grid-options) - Created for each Special Column provided to AdapTable (of which there are 3 types): - [Action Columns](https://www.adaptabletools.com/docs/handbook-action-column/index.md) - [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - [FreeText Columns](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) - Matching columns that are dynamically created by AG Grid - these include: - [Row Grouped Columns](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md) - [Pivot Result Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md) - [Tree Grid Key Columns](https://www.adaptabletools.com/docs/handbook-tree-data-grid/index.md) - [Selection Column](https://www.adaptabletools.com/docs/handbook-layouts-table-row-selection/index.md) See below for details on how AdapTable sets the properties of the AdapTable Column ## AdapTable Column Properties Adaptable Columns are defined using the [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md) object which contains a large number of properties. These properties are evaluated by AdapTable when the Application starts. ### AdaptableColumn Object: Full Properties The [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md) object is derived from [`AdaptableColumnBase`](https://www.adaptabletools.com/docs/reference/adaptablecolumnbase.md) which contains these properties: | Property | Type | Description | | --- | --- | --- | | [columnId](https://www.adaptabletools.com/docs/reference/adaptablecolumnbase.md#columnid) | `string` | Name of Column in AG Grid (e.g. field or colId) | | [columnTypes](https://www.adaptabletools.com/docs/reference/adaptablecolumnbase.md#columntypes) | `string[]` | Column Types of the Column | | [dataType](https://www.adaptabletools.com/docs/reference/adaptablecolumnbase.md#datatype) | [`AdaptableColumnDataType`](https://www.adaptabletools.com/docs/reference/adaptablecolumndatatype.md) | DataType of the Column | | [friendlyName](https://www.adaptabletools.com/docs/reference/adaptablecolumnbase.md#friendlyname) | `string` | How Column is referred to in Adaptable UI; `Caption` property in AG Grid | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/adaptablecolumnbase.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | The full list of properties in the [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md) object is: | Property | Type | Description | | --- | --- | --- | | [aggregatable](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#aggregatable) | `boolean` | Is Column able to display aggregations (e.g. 'sum') when grouped | | [aggregationFunction](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#aggregationfunction) | `string` | Custom Aggregation function for the Column | | [availableAggregationFunctions](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#availableaggregationfunctions) | `string[]` | Available Aggregations for the Column | | [columnGroup](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#columngroup) | [`AdaptableColumnGroup`](https://www.adaptabletools.com/docs/reference/adaptablecolumngroup.md) | The parent Column group (if Column belongs to one) | | [exportable](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#exportable) | `boolean` | Whether the Column can be included in Reports | | [field](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#field) | `Extract` | Field in the row to get cell data from | | [fieldOnly](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#fieldonly) | `boolean` | Is the Column ONLY available as a field and never visible | | [filterable](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#filterable) | `boolean` | Is Column able to be filtered | | [flex](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#flex) | `number` | Flex details of the Column | | [groupable](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#groupable) | `boolean` | Can Column form a Row Group | | [hideable](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#hideable) | `boolean` | Can Column be removed from the grid | | [isActionColumn](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#isactioncolumn) | `boolean` | Is Column an Action Column | | [isCalculatedColumn](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#iscalculatedcolumn) | `boolean` | Is Column a Calculated Column | | [isFixed](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#isfixed) | `boolean` | Is Column pinned or locked into position | | [isFreeTextColumn](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#isfreetextcolumn) | `boolean` | Is Column a Free Text Column | | [isGeneratedPivotResultColumn](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#isgeneratedpivotresultcolumn) | `boolean` | Is Column a generated Pivot Result Column | | [isGeneratedRowGroupColumn](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#isgeneratedrowgroupcolumn) | `boolean` | Is Column a generated Row Group Column | | [isGeneratedSelectionColumn](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#isgeneratedselectioncolumn) | `boolean` | Is Column a generated Selection Column | | [isGrouped](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#isgrouped) | `boolean` | Is Column currently Row-Grouped | | [isPivotTotalColumn](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#ispivottotalcolumn) | `boolean` | Is Column a Pivot Total Column (GrandTotal, GroupTotal, AggregationTotal) | | [isPrimaryKey](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#isprimarykey) | `boolean` | Is this the Primary Key Column | | [isSparkline](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#issparkline) | `boolean` | Is it a Sparkline Column | | [isTreeColumn](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#istreecolumn) | `boolean` | Whether Column is the Tree Column (in Tree View) | | [isUIHiddenColumn](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#isuihiddencolumn) | `boolean` | Whether Column is always hidden in UI but still available programmatically | | [moveable](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#moveable) | `boolean` | Can Column be moved at run-time to a new position | | [pinned](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#pinned) | `'left' \| 'right' \| false` | The pinned position of the Column | | [pivotable](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#pivotable) | `boolean` | Can Column be used in a Pivot Layout | | [queryable](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#queryable) | `boolean` | Can the Column be in included in Queries / Expressions | | [readOnly](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#readonly) | `boolean` | Is Column editable; returns FALSE if Column has conditional/dynamic editability, assuming some rows are editable | | [resizable](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#resizable) | `boolean` | Is Column resizable | | [sortable](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#sortable) | `boolean` | Is Column sortable | | [userAllowedAggFuncs](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#userallowedaggfuncs) | `string[]` | `allowedAggFuncs` from the column `colDef` or `defaultColDef` as supplied in Grid Options (before Adaptable rewrites `allowedAggFuncs` for the standard Value Aggregation menu). | | [visible](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#visible) | `boolean` | Is Column currently visible | | [width](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#width) | `number` | Column width | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | However, these properties fall into 4 broad groups which makes them easier to reason about. ### Identity Props The "Identity Props" define who the Column is. They are probably the most important, and frequently used, properties and include: #### columnId The `columnId` property is the primary way of referring to the Column, and what is generally used in [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md). It is the stable key for the Column throughout AdapTable and maps directly to the AG Grid `colId`. As AG Grid derives `colId` from the `field` property when one is not explicitly provided, the `columnId` will usually match the Column's `field`. If you are holding an AG Grid `ColDef` and need the matching AdapTable Column, use [`getColumnForColDef`](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnforcoldef) rather than trying to work out the `columnId` yourself. #### friendlyName The `friendlyName` property sets how the Column is referred to throughout the AdapTable UI. This includes the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) and all panels in the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md). It is usually derived automatically from the `headerName` property in the AG Grid Column definition, but it can be provided explicitly in the `columnFriendlyName` function property in [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md). This is useful where you might have multiple columns with the same header (e.g. 'Price' or 'Bid') and you want to be able to differentiate between them in the UI #### dataType The `dataType` important property determines whether the Column is a number, string, date, boolean etc. This influences many things in AdapTable e.g. what [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) are available. AdapTable derives the value of the DataType, in the first instance by using the [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) of the AG Grid Column Definition if provided. - The [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) is assigned to the Column's AG Grid `ColDef` definition using the `cellDataType` property - It is strongly advised that **all AG Grid Col Definitions should include this property** #### columnTypes The `columnTypes` property is based off the `types` property of the AG Grid Column Definition. AdapTable will add additional values to this prop in some use cases (as detailed [in this tutorial](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md)). ### How are the 'Identity' Properties set? This table illustrates how the value for each property is worked out by AdapTable: | Property | AG Grid Column Property | Action Column | Calculated Column | FreeText Column | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | | `ColumnDefs` in [GridOptions](https://www.ag-grid.com/javascript-data-grid/grid-interface/#grid-options) | [User Interface Options](https://www.adaptabletools.com/docs/ui-technical-reference/index.md) | [Calculated Column InitialState](https://www.adaptabletools.com/docs/handbook-calculated-column-technical-reference/index.md) | [FreeText Column InitialState](https://www.adaptabletools.com/docs/handbook-freetext-column-technical-reference/index.md) | | `columnId` | `field` (and then `colId`) | `columnId` | `ColumnId` | `ColumnId` | | `friendlyName` | AG Grid ColumnAPI function: `getDisplayNameForColumn` | `friendlyName` | `FriendlyName` | `FriendlyName` | | `dataType` | From [AG Grid cellDataType](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) if provided; otherwise guesses from first Row's data | n/a | `DataType` | `DataType` | | `columnTypes` | From [AG Grid type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) | `actionColumn` | `calculatedColumn` | `freeTextColumn` | See [Column Types: Scope](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) for how to provide column types that are available when scoping objects ### Capability flags These properties define what a User is allowed to _do_ with the Column: `sortable`, `filterable`, `groupable`, `pivotable`, `aggregatable`, `queryable`, `exportable`, `moveable`, `hideable`, `readOnly`. - Many of these are derived from functions you supply in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) - e.g. `exportable` from `isColumnExportable`, `queryable` from `isColumnQueryable` ### Column-kind flags These properties define what _sort_ of Column it is: `isCalculatedColumn`, `isFreeTextColumn`, `isActionColumn`, `isPivotTotalColumn`, `isGeneratedRowGroupColumn`, `isGeneratedSelectionColumn`, `isGeneratedPivotResultColumn`, `isSparkline` ### Live grid-state These properties define the Column's current state in the Grid: `visible`, `pinned`, `width`, `flex`, `isGrouped`, `isFixed` - The **Live grid-state** properties reflect the state of the Column at the moment the object was retrieved - If the Column is subsequently moved, pinned, or grouped etc, a previously retrieved `AdaptableColumn` will be stale - Do **not cache** these values - Re-fetch the Column via [Column API](https://www.adaptabletools.com/docs/index.md#column-api) (e.g. [`getColumnWithColumnId`](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnwithcolumnid)) whenever you need the current state ## Types of AdapTable Columns It is worth dividing up AdapTable Columns into 3 groups. The type of the AdapTable Column also influences **how** AdapTable evaluates the associated properties ### Regular Columns Regular columns are those which are defined initially in AG Grid GridOptions object. AdapTable will work out the values for that Column's properties in AdapTable Column in 2 ways: - using the values provided in the AG Grid Column Definition Examples are `field`, `groupable`, `movable`, `sortable` - all based off similar properties in Grid Options - reading some properties provided in Adaptable Options, for example: - `exportable` - derived from the `isColumnExportable` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) - `queryable` - derived from `isColumnQueryable` property [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md) ### Special Columns AdapTable can create 3 'Special Columns' which are not defined in Grid Options but through AdapTable itself: - [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - [FreeText Columns](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) - [Action Columns](https://www.adaptabletools.com/docs/handbook-action-column/index.md) In these cases AdapTable uses a combination of: - properties provided in the object definitions in [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md) - sensible defaults for the Column (e.g. Action Columns have `readOnly` set to _true_) ### Derived Columns There are various use cases where AG Grid will create a create a Column that is **not provided** by the developer in ColumnDefs. These include: When this happens AdapTable will always create a matching Column, also provided dynamically - [Row Grouped Columns](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md) - [Pivot Result Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md) - [Tree Grid Key Columns](https://www.adaptabletools.com/docs/handbook-tree-data-grid/index.md) - [Selection Column](https://www.adaptabletools.com/docs/handbook-layouts-table-row-selection/index.md) ## Using AdapTable Columns **Run-time users** leverage AdapTable Columns continuously but indirectly through AG Grid. The overwhelming majority of users of AdapTable will not need to be aware of the existence of AdapTable Columns. **Developers** will frequently access AdapTable Columns since they are often contained in Context objects supplied to functions, and used elsewhere in AdapTable (e.g. in the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md)). Developers **will never create** AdapTable Columns as they are provided dynamically by AdapTable Most commonly you retrieve a Column through the [Column API](https://www.adaptabletools.com/docs/index.md#column-api) using its `columnId` and then read its properties: ```ts // get a single Column and inspect it const priceColumn = adaptableApi.columnApi.getColumnWithColumnId('price'); if (priceColumn) { console.log(priceColumn.friendlyName); // e.g. 'Bid Price' console.log(priceColumn.dataType); // e.g. 'number' console.log(priceColumn.queryable); // capability flag } ``` You can use the **column-kind flags** to work out what sort of Column you are dealing with: ```ts const column = adaptableApi.columnApi.getColumnWithColumnId('rating'); if (column?.isCalculatedColumn) { // handle Calculated Columns differently to regular Columns } ``` If you are working with AG Grid directly and have a `ColDef` (for example inside an AG Grid callback), you can get straight to the matching AdapTable Column: ```ts // map an AG Grid ColDef to its AdapTable Column const abColumn = adaptableApi.columnApi.getColumnForColDef(colDef); ``` ## Reference ### Column Options The [`ColumnOptions`](https://www.adaptabletools.com/docs/reference/columnoptions.md) section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) contains properties for managing Adaptable Columns. This includes an option to show a warning if it cannot find a provided Column. ### `showMissingColumnsWarning` Show a Warning when Columns are Missing By default AdapTable will display an error message in the Console if it encounters a Column that has not been defined in AG Grid GridOptions. A common occurrence is if the [Primary Key](https://www.adaptabletools.com/docs/getting-started-primary-key/index.md) property exists in the Data Source but is not an AG Grid column Set this property to false to turn off this warning: ```ts {4} // Do not show Error Messages in Console for missing Columns const adaptableOptions: AdaptableOptions = { columnOptions: { showMissingColumnsWarning: false, }, }; ``` #### Column Options Properties | Property | Type | Description | Default | | --- | --- | --- | --- | | [addColumnGroupToColumnFriendlyName](https://www.adaptabletools.com/docs/reference/columnoptions.md#addcolumngrouptocolumnfriendlyname) | `boolean` | Appends the name of the Column Group to a Column's Friendly Name | false | | [columnFriendlyName](https://www.adaptabletools.com/docs/reference/columnoptions.md#columnfriendlyname) | `(columnFriendlyNameContext: `[`ColumnFriendlyNameContext`](https://www.adaptabletools.com/docs/reference/columnfriendlynamecontext.md)`) => string \| undefined` | Provide an alternative Friendly Name for a Column | undefined | | [columnHeader](https://www.adaptabletools.com/docs/reference/columnoptions.md#columnheader) | `(context: `[`ColumnHeaderContext`](https://www.adaptabletools.com/docs/reference/columnheadercontext.md)`) => string` | Provide a custom Header Name for a Table or Pivot Column | | | [columnTypes](https://www.adaptabletools.com/docs/reference/columnoptions.md#columntypes) | `TypeHint[] \| ((context: `[`ColumnTypesContext`](https://www.adaptabletools.com/docs/reference/columntypescontext.md)`) => TypeHint[])` | Optional list of Column Types - used for Scope and creating Special Columns | Empty Array | | [showMissingColumnsWarning](https://www.adaptabletools.com/docs/reference/columnoptions.md#showmissingcolumnswarning) | `boolean` | Log warning to console if AdapTable cannot find a column | true | ### Column API AdapTable provides the Column API class in [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) to enable programmatic access to all the AdapTable Columns which have been created. This includes a plethora of methods giving full access to the full range of properties in each Column: | Method | Returns | Description | | --- | --- | --- | | [addColumnsToSelection(columnIds)](https://www.adaptabletools.com/docs/reference/columnapi.md#addcolumnstoselection) | `void` | Adds (highlights) a group of Columns to any existing selection | | [addColumnToSelection(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#addcolumntoselection) | `void` | Adds (highlights) a Column to any existing selection | | [autosizeAllColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#autosizeallcolumns) | `void` | Autosizes all Columns in the Grid | | [autosizeColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#autosizecolumn) | `void` | AutoSizes a Column | | [autosizeColumns(columnIds)](https://www.adaptabletools.com/docs/reference/columnapi.md#autosizecolumns) | `void` | Autosizes given Columns | | [doesColumnExist(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#doescolumnexist) | `boolean` | Checks if Column has already been created | | [getAggregatableColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getaggregatablecolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Aggregatable Columns | | [getAGGridColDefForColumnId(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#getaggridcoldefforcolumnid) | `ColDef \| ColGroupDef` | Returns AG Grid ColDef for a given ColumnId | | [getAGGridColumnForColumnId(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#getaggridcolumnforcolumnid) | `Column` | Returns the AG Grid Column for a given ColumnId | | [getArrayColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getarraycolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all array columns (number, tuple-number, object-number & text) | | [getBooleanColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getbooleancolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all boolean Columns | | [getColumnDataTypeForColumnId(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumndatatypeforcolumnid) | [`AdaptableColumnDataType`](https://www.adaptabletools.com/docs/reference/adaptablecolumndatatype.md)` \| undefined` | Returns Data Type for the Column with given ColumnId | | [getColumnForColDef(colDef)](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnforcoldef) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)` \| undefined` | Returns the AdapTable Column that maps to a given AG Grid ColDef | | [getColumnIdForFriendlyName(friendlyName)](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnidforfriendlyname) | `string` | Retrieves ColumnId for Column with given Friendly Name | | [getColumnIdsForFriendlyNames(friendlyNames)](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnidsforfriendlynames) | `string[]` | Retrieves ColumnIds for Columns with given Friendly Names | | [getColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Columns available (including hidden, special) | | [getColumnsByColumnType(columnType)](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnsbycolumntype) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all columns of a given columnType | | [getColumnSummaryForColumnId(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnsummaryforcolumnid) | [`AdaptableColumnSummary`](https://www.adaptabletools.com/docs/reference/adaptablecolumnsummary.md) | Gets summary info for a column including filters and unique values | | [getColumnsWithColumnIds(columnIds)](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnswithcolumnids) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Retrieves Adaptable Columns with given ColumnIds | | [getColumnsWithDataType(dataType)](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnswithdatatype) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Columns that have given DataType | | [getColumnsWithFriendlyNames(friendlyNames)](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnswithfriendlynames) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Retrieves Adaptable Columns with given Friendly names | | [getColumnTypes()](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumntypes) | `string[]` | Returns available columns types defined under columnOptions.columnTypes | | [getColumnWithColumnId(columnId, logWarning)](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnwithcolumnid) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)` \| undefined` | Retrieves AdapTable Column with given ColumnId | | [getColumnWithFriendlyName(columnName, logWarning)](https://www.adaptabletools.com/docs/reference/columnapi.md#getcolumnwithfriendlyname) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md) | Retrieves AdapTable Column with given Friendly name | | [getDateColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getdatecolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Date Columns | | [getDefaultAggFunc(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#getdefaultaggfunc) | `string` | Returns the default Aggregation Function for a Column | | [getExportableColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getexportablecolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Exportable Columns | | [getFilterableColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getfilterablecolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Sortable Columns | | [getFriendlyNameForColumnId(columnId, layout)](https://www.adaptabletools.com/docs/reference/columnapi.md#getfriendlynameforcolumnid) | `string` | Retrieves Friendly Name of Column with given ColumnId | | [getFriendlyNamesForColumnIds(columnIds)](https://www.adaptabletools.com/docs/reference/columnapi.md#getfriendlynamesforcolumnids) | `string[]` | Retrieves Friendly Names for given ColumnIds | | [getGroupableColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getgroupablecolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Groupable Columns | | [getNonSpecialColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getnonspecialcolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all UI available columns excluding Action, FreeText and Calculated Columns | | [getNumberArrayColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getnumberarraycolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all number-array columns | | [getNumericArrayColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getnumericarraycolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all numeric array columns (number, tuple-number, object-number) | | [getNumericColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getnumericcolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all numeric Columns | | [getObjectNumberArrayColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getobjectnumberarraycolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all object-number-array columns e.g. [x:1,y:2,x:3,y:4] | | [getPivotableColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getpivotablecolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Pivotable Columns | | [getPrimaryKeyColumn()](https://www.adaptabletools.com/docs/reference/columnapi.md#getprimarykeycolumn) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)` \| undefined` | Retrieves current Primary Key Column in AdapTable. It may be undefined if the primary key is auto-generated, or it is NOT mapped to a column. | | [getQueryableColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getqueryablecolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Queryable Columns | | [getRowGroupedColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getrowgroupedcolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all columns currently Row Grouped | | [getSortableColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getsortablecolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Sortable Columns | | [getSpecialColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getspecialcolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns any Action, FreeText and Calculated Columns | | [getTextArrayColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#gettextarraycolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all string array Columns | | [getTextColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#gettextcolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Text Columns | | [getTupleNumberArrayColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#gettuplenumberarraycolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all tuple-number-array columns e.g. [[1,2],[3,4]] | | [getUIAvailableColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getuiavailablecolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all Columns that can be displayed in UI (excludes always hidden cols) | | [getUIHiddenColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getuihiddencolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns Columns that are always hidden in UI (but available for Expressions) | | [getVisibleColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#getvisiblecolumns) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns all visible Columns | | [hasArrayDataType(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#hasarraydatatype) | `boolean` | Checks if the Column with the given `columnId` has any Array-like DataType (`TextArray`,`NumberArray`,`TupleNumberArray` or `ObjectNumberArray`) | | [hasBooleanDataType(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#hasbooleandatatype) | `boolean` | Checks if the Column with the given `columnId` has DataType Boolean | | [hasColumnType(columnIdentifier, columnType)](https://www.adaptabletools.com/docs/reference/columnapi.md#hascolumntype) | `boolean` | Checks if the Column with given Column Identifier (columnId or ColDef) has a specific Column Type | | [hasDateDataType(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#hasdatedatatype) | `boolean` | Checks if the Column with the given `columnId` has DataType Date | | [hasNumberDataType(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#hasnumberdatatype) | `boolean` | Checks if the Column with the given `columnId` has DataType Number | | [hasNumericArrayDataType(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#hasnumericarraydatatype) | `boolean` | Checks if the Column with the given `columnId` has an Numeric Array-like DataType (`NumberArray`,`TupleNumberArray` or `ObjectNumberArray`) | | [hasTextArrayDataType(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#hastextarraydatatype) | `boolean` | Checks if the Column with the given `columnId` has a Text Array-like DataType (`TextArray`) | | [hideColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#hidecolumn) | `void` | Hides a Column from Grid | | [isActionColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#isactioncolumn) | `boolean` | Checks if Column with given ColumnId is an Action Column | | [isAgGridGeneratedColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#isaggridgeneratedcolumn) | `boolean` | Whether column is auto generated by AG Grid (for selection, grouping, pivoting etc) | | [isAutoRowGroupColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#isautorowgroupcolumn) | `boolean` | Checks if Column with given ColumnId is a row-group Column automatically generated by AG Grid | | [isAutoRowGroupColumnForMulti(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#isautorowgroupcolumnformulti) | `boolean` | Checks if Column with given ColumnId is a row-group Column automatically generated by AG Grid, for row-grouping with group display type = 'multi' | | [isAutoRowGroupColumnForSingle(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#isautorowgroupcolumnforsingle) | `boolean` | Checks if Column with given ColumnId is a row-group Column automatically generated by AG Grid, for row-grouping with group display type = 'single' | | [isCalculatedColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#iscalculatedcolumn) | `boolean` | Checks if Column with given ColumnId is a Calculated Column | | [isColumnInGrid(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#iscolumningrid) | `boolean` | Returns true if the given Column exists in the Grid | | [isFdc3Column(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#isfdc3column) | `boolean` | Checks if Column with given ColumnId is a FDC3 Column | | [isFreeTextColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#isfreetextcolumn) | `boolean` | Checks if Column with given ColumnId is a Free Text Column | | [isPivotAggColumnWithNoPivotColumns(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#ispivotaggcolumnwithnopivotcolumns) | `boolean` | Checks if Column with given ColumnId is a pivot aggregation column in a pivot layout with no pivot columns. When PivotColumns is empty, aggregation columns keep their original IDs instead of getting a 'pivot_' prefix. | | [isPivotResultColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#ispivotresultcolumn) | `boolean` | Checks if Column with given ColumnId is a pivot Column automatically generated by AG Grid | | [isSelectionColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#isselectioncolumn) | `boolean` | Checks if Column with given ColumnId is a Selection (Checkbox) Column automatically generated by AG Grid | | [isSpecialColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#isspecialcolumn) | `boolean` | Checks if Column with given ColumnId is a Special (i.e. calculated, freetext or action) Column | | [openColumnInfoSettingsPanel()](https://www.adaptabletools.com/docs/reference/columnapi.md#opencolumninfosettingspanel) | `void` | Opens Settings Panel with Column Info section selected and visible | | [selectAllColumns()](https://www.adaptabletools.com/docs/reference/columnapi.md#selectallcolumns) | `void` | Selects all Columns | | [selectColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#selectcolumn) | `void` | Selects (highlights) a Column | | [selectColumns(columnIds)](https://www.adaptabletools.com/docs/reference/columnapi.md#selectcolumns) | `void` | Selects (highlights) group of Columns | | [setColumnCaption(columnId, caption)](https://www.adaptabletools.com/docs/reference/columnapi.md#setcolumncaption) | `void` | Sets a new Caption / Header for a Column (only for current Layout) | | [showColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnapi.md#showcolumn) | `void` | Makes a Column visible | --- # Configuring Column Header Canonical page: https://www.adaptabletools.com/docs/dev-guide-columns-column-headers - AdapTable users are able to change the Header / Caption of a Column in AG Grid in 2 ways: - Changes configured in a particular Layout - Changes set through Column Options By default, AdapTable will show as the header (or caption) of the Column (ie. the text that appears in the Header Bar) the default value provided in AG Grid's ColumnDefs. However this can be changed in AdapTable in 2 ways (using this order of evaluation): - on a [per-Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) basis using the `ColumnHeaders` property - via the `columnHeader` function in [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) ## Per Layout The highest level of priority are changes made to a given [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) using the `ColumnHeaders` property. - This enables the same Column to have different Headers / Captions in 2 Layouts - It also allows the Column's Header to be set at run-time via the AdapTable UI A custom Column Header can be set in a Layout (using the `ColumnHeaders` property) in many ways: - In [Layout Initial State](https://www.adaptabletools.com/docs/handbook-layouts-table-column-headers/index.md) (i.e. by developers at design-time) - Using the `Change Caption` menu option in each [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md) - In the `Columns` section of the Layout Wizard (via the dropdown which opens an expanded section) - Programmatically using the `setColumnCaption` function in [Layout API](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) - AG Grid makes it easy to wrap Column Headers - useful when the header text is wider than the cell text - The `wrapHeaderText` & `autoHeaderHeight` props in Column Defs, when set to *true*, creates the necessary effect **Example: Custom Column Headers Layout** Providing Alternative Column Headers in a Layout - This demo shows how to change the Column Header on a per-Layout basis - In the Initial State for the `Standard` Layout we change 'Name' to `JavaScript Framework` and 'Gihub Stars' to `Fans` - Note: we set `wrapHeaderText` and `autoHeaderHeight` to *true* in Column Def's to create a better visual effect - We provide a Dashboard button to allow the Header for "Updated" to be set via the [Layout API](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) - Switch between Layouts and note that the `Grouped` Layout contains the original Column Headers - Change a Column Header using the `Change Header` Menu Item in the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md) - Change another Column's Header by using the Layout Editor's Wizard ```ts import { AdaptableButton, DashboardButtonContext, } from '@adaptabletools/adaptable'; import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'tradeId', userName: 'Demo User', adaptableId: 'Column Headers Layout', dashboardOptions: { customDashboardButtons: [ { label: 'Change "Updated" Column Header', buttonStyle: { tone: 'neutral', variant: 'outlined', }, onClick: ( _button: AdaptableButton, context: DashboardButtonContext ) => { context.adaptableApi.layoutApi.setColumnCaption( 'updated_at', 'Most Recently Changed' ); }, }, ], }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'language', 'github_stars', 'license', 'updated_at', 'has_wiki', 'created_at', 'pushed_at', 'github_watchers', ], ColumnHeaders: { github_stars: 'Fans', name: 'JavaScript Framework', }, ColumnSizing: { name: {Width: 120}, }, }, { Name: 'Grouped Layout', RowGroupedColumns: ['license'], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', ], }, ], }, }, }; ``` ```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, wrapHeaderText: true, autoHeaderHeight: true, }, columnDefs: columnDefs, rowData: rowData, sideBar: true, }; ``` ## Using a Function The `columnHeader` function in [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) provides a more configurable way to change Column Headers. Changes made to Column Headers in a [Layout](#per-layout) (either in Layout Initial State or in the UI) will take precedence The function allows headers to be programmatically set for each Column (or type of Column). The function's context supports many different categories of column, including dynamically created ones. ### `columnHeader` Provide Custom Column Headers This function allows developers to provide custom Headers for any Column in AG Grid. It receives a [`ColumnHeaderContext`](https://www.adaptabletools.com/docs/reference/columnheadercontext.md) object and returns a string. The actual Context object provided by the function changes based on the type of the Column. There are 9 different types of Column supported. Base Context All context objects derive from [`BaseColumnHeaderContext`](https://www.adaptabletools.com/docs/reference/basecolumnheadercontext.md) which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [currentLayout](https://www.adaptabletools.com/docs/reference/basecolumnheadercontext.md#currentlayout) | [`Layout`](https://www.adaptabletools.com/docs/reference/layout.md) | Current Layout | | [currentLayoutName](https://www.adaptabletools.com/docs/reference/basecolumnheadercontext.md#currentlayoutname) | `string` | Name of Current Layout | | [currentLayoutType](https://www.adaptabletools.com/docs/reference/basecolumnheadercontext.md#currentlayouttype) | `'table' \| 'pivot'` | Type (table/pivot) of Current Layout | | [defaultHeaderName](https://www.adaptabletools.com/docs/reference/basecolumnheadercontext.md#defaultheadername) | `string` | Default header name for Column | | [adaptableContext](https://www.adaptabletools.com/docs/reference/basecolumnheadercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | Table Columns Standard Table Layout Columns use [`TableColumnHeaderContext`](https://www.adaptabletools.com/docs/reference/tablecolumnheadercontext.md): | Property | Type | Description | | --- | --- | --- | | [aggregation](https://www.adaptabletools.com/docs/reference/tablecolumnheadercontext.md#aggregation) | `string` | Aggregation function of Column (optional) | | [columnId](https://www.adaptabletools.com/docs/reference/tablecolumnheadercontext.md#columnid) | `string` | Id of the Column | | [columnType](https://www.adaptabletools.com/docs/reference/tablecolumnheadercontext.md#columntype) | `'tableColumn'` | Table Column (created in Table Layouts) | | [adaptableContext](https://www.adaptabletools.com/docs/reference/tablecolumnheadercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | Table Group Columns Table Layout Columns which are in a Column Group use [`TableColumnGroupHeaderContext`](https://www.adaptabletools.com/docs/reference/tablecolumngroupheadercontext.md): | Property | Type | Description | | --- | --- | --- | | [childrenColumnIds](https://www.adaptabletools.com/docs/reference/tablecolumngroupheadercontext.md#childrencolumnids) | `string[]` | Ids of Column Group's children | | [columnType](https://www.adaptabletools.com/docs/reference/tablecolumngroupheadercontext.md#columntype) | `'tableColumnGroup'` | Table Column Group (used when Column Grouping in Table Layouts) | | [groupId](https://www.adaptabletools.com/docs/reference/tablecolumngroupheadercontext.md#groupid) | `string` | Id of Column Group | | [state](https://www.adaptabletools.com/docs/reference/tablecolumngroupheadercontext.md#state) | `'expanded' \| 'collapsed'` | Expanded / Collapsed state of Column Group | | [adaptableContext](https://www.adaptabletools.com/docs/reference/tablecolumngroupheadercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | Auto Group Columns Auto Group Columns (created by AG Grid when Row Grouping is active) use [`AutoGroupColumnHeaderContext`](https://www.adaptabletools.com/docs/reference/autogroupcolumnheadercontext.md): | Property | Type | Description | | --- | --- | --- | | [columnId](https://www.adaptabletools.com/docs/reference/autogroupcolumnheadercontext.md#columnid) | `string` | Id of the Column | | [columnType](https://www.adaptabletools.com/docs/reference/autogroupcolumnheadercontext.md#columntype) | `'autoGroupColumn'` | Auto-generated Row Group Column (when RowGroupDisplayType is `single`) | | [groupedColumnIds](https://www.adaptabletools.com/docs/reference/autogroupcolumnheadercontext.md#groupedcolumnids) | `string[]` | Ids of all Row Grouped Columns | | [adaptableContext](https://www.adaptabletools.com/docs/reference/autogroupcolumnheadercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | Row Group Columns Row Grouped Columns (created by AG Grid when Row Grouping is active) use [`RowGroupColumnHeaderContext`](https://www.adaptabletools.com/docs/reference/rowgroupcolumnheadercontext.md): | Property | Type | Description | | --- | --- | --- | | [columnId](https://www.adaptabletools.com/docs/reference/rowgroupcolumnheadercontext.md#columnid) | `string` | Id of the Column | | [columnType](https://www.adaptabletools.com/docs/reference/rowgroupcolumnheadercontext.md#columntype) | `'rowGroupColumn'` | A Row Grouped Column (created in both Table and Pivot Layout) | | [groupColumnId](https://www.adaptabletools.com/docs/reference/rowgroupcolumnheadercontext.md#groupcolumnid) | `string` | Id of Row Grouped Column | | [adaptableContext](https://www.adaptabletools.com/docs/reference/rowgroupcolumnheadercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | Pivot Group Columns Pivot Group Columns are created by AG Grid for each distinct value in a Pivot Column, and use [`PivotColumnGroupHeaderContext`](https://www.adaptabletools.com/docs/reference/pivotcolumngroupheadercontext.md): | Property | Type | Description | | --- | --- | --- | | [columnType](https://www.adaptabletools.com/docs/reference/pivotcolumngroupheadercontext.md#columntype) | `'pivotColumnGroup'` | Pivot Column Group (created for each distinct value in a PivotColumn) | | [groupId](https://www.adaptabletools.com/docs/reference/pivotcolumngroupheadercontext.md#groupid) | `string` | Id of generated Column Group | | [pivotKeys](https://www.adaptabletools.com/docs/reference/pivotcolumngroupheadercontext.md#pivotkeys) | `string[]` | Pivot Keys for Column Group | | [state](https://www.adaptabletools.com/docs/reference/pivotcolumngroupheadercontext.md#state) | `'expanded' \| 'collapsed'` | Expanded / Collapsed state of Column Group | | [adaptableContext](https://www.adaptabletools.com/docs/reference/pivotcolumngroupheadercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | Pivot Result Columns Pivot Result Columns are dynamically created by AG Grid for each combination of Pivot Column value and Pivot Aggregation, and use [`PivotResultColumnHeaderContext`](https://www.adaptabletools.com/docs/reference/pivotresultcolumnheadercontext.md): | Property | Type | Description | | --- | --- | --- | | [aggregatedColumnId](https://www.adaptabletools.com/docs/reference/pivotresultcolumnheadercontext.md#aggregatedcolumnid) | `string` | Id of Pivot Aggregated Column | | [aggregation](https://www.adaptabletools.com/docs/reference/pivotresultcolumnheadercontext.md#aggregation) | `string` | Aggregation function of Column | | [columnId](https://www.adaptabletools.com/docs/reference/pivotresultcolumnheadercontext.md#columnid) | `string` | Id of generated Column | | [columnType](https://www.adaptabletools.com/docs/reference/pivotresultcolumnheadercontext.md#columntype) | `'pivotResultColumn'` | Pivot Result Column (unique intersection of PivotAggregationColumn and PivotColumn) | | [pivotKeys](https://www.adaptabletools.com/docs/reference/pivotresultcolumnheadercontext.md#pivotkeys) | `string[]` | Current Pivot Keys | | [adaptableContext](https://www.adaptabletools.com/docs/reference/pivotresultcolumnheadercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | Pivot Grand Total Columns Pivot Grand Total Columns (used for [Pivot Totalling](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md)) use [`PivotGrandTotalHeaderContext`](https://www.adaptabletools.com/docs/reference/pivotgrandtotalheadercontext.md): | Property | Type | Description | | --- | --- | --- | | [aggregatedColumnId](https://www.adaptabletools.com/docs/reference/pivotgrandtotalheadercontext.md#aggregatedcolumnid) | `string` | Id of Pivot Aggregated Column | | [aggregation](https://www.adaptabletools.com/docs/reference/pivotgrandtotalheadercontext.md#aggregation) | `string` | Aggregation function of Column | | [columnType](https://www.adaptabletools.com/docs/reference/pivotgrandtotalheadercontext.md#columntype) | `'pivotGrandTotal'` | Pivot Grand Total Column | | [adaptableContext](https://www.adaptabletools.com/docs/reference/pivotgrandtotalheadercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | Pivot Column Total Columns Pivot Column Total Columns (also used for [Pivot Totalling](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md)) use [`PivotColumnTotalHeaderContext`](https://www.adaptabletools.com/docs/reference/pivotcolumntotalheadercontext.md): | Property | Type | Description | | --- | --- | --- | | [aggregation](https://www.adaptabletools.com/docs/reference/pivotcolumntotalheadercontext.md#aggregation) | `string` | Aggregation function of Column | | [columnType](https://www.adaptabletools.com/docs/reference/pivotcolumntotalheadercontext.md#columntype) | `'pivotColumnTotal'` | Pivot Column Total | | [pivotColumnId](https://www.adaptabletools.com/docs/reference/pivotcolumntotalheadercontext.md#pivotcolumnid) | `string` | Id of Pivot Column | | [pivotKey](https://www.adaptabletools.com/docs/reference/pivotcolumntotalheadercontext.md#pivotkey) | `string` | Key (i.e. column value) of Pivot Column | | [adaptableContext](https://www.adaptabletools.com/docs/reference/pivotcolumntotalheadercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | Pivot Aggregation Total Columns Pivot Aggregation Total Columns (again also used for [Pivot Totalling](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md)) use [`PivotAggregationTotalHeaderContext`](https://www.adaptabletools.com/docs/reference/pivotaggregationtotalheadercontext.md): | Property | Type | Description | | --- | --- | --- | | [aggregatedColumnId](https://www.adaptabletools.com/docs/reference/pivotaggregationtotalheadercontext.md#aggregatedcolumnid) | `string` | Id of Aggregated Column | | [aggregation](https://www.adaptabletools.com/docs/reference/pivotaggregationtotalheadercontext.md#aggregation) | `string` | Aggregation function of Column | | [columnType](https://www.adaptabletools.com/docs/reference/pivotaggregationtotalheadercontext.md#columntype) | `'pivotAggregationTotal'` | Pivot Aggregation Total Column | | [pivotColumnId](https://www.adaptabletools.com/docs/reference/pivotaggregationtotalheadercontext.md#pivotcolumnid) | `string` | Id of Pivot Column | | [pivotKey](https://www.adaptabletools.com/docs/reference/pivotaggregationtotalheadercontext.md#pivotkey) | `string` | Key (i.e. column value) of Pivot Column | | [adaptableContext](https://www.adaptabletools.com/docs/reference/pivotaggregationtotalheadercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | **Example: Custom Column Headers Function** Providing Alternative Column Headers via a function - This demo shows how to change the Column Header programmatically. We change the Header for various types of columns (visible via different Layouts): - For `tableColumn` we change 'Name' to `JS Framework` (see `Table Layout`) - For `autoGroupColumn` we change the header to "My Row Group" (see `Row Grouped Layout`) - For `tableColumnGroup` we change the header to "My Column Group" (see `Column Group Layout`) - For `pivotResultColumn` we add prefix of "Agg" to header (see `Pivot Layout`) - For `pivotColumnGroup` we add prefix of "PC" to header (also see `Pivot Layout`) - Switch between Layouts and see the different Headers - Change the Language / JavasScript Framework Column Header by using the Layout Editor's Wizard and not it takes precedence ```ts import {AdaptableOptions, ColumnHeaderContext} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'tradeId', userName: 'Demo User', adaptableId: 'Column Headers Function', columnOptions: { columnHeader: (context: ColumnHeaderContext) => { const {columnType, defaultHeaderName} = context; if (columnType == 'tableColumn') { if (context.columnId == 'name') { return 'JS Framework'; } } else if ( columnType == 'autoGroupColumn' && context.currentLayoutType == 'table' ) { return 'My Row Group'; } else if (columnType == 'pivotResultColumn') { return `Agg: ${defaultHeaderName}`; } else if ( columnType == 'tableColumnGroup' && context.currentLayoutType == 'table' ) { return 'My Column Group'; } else if (columnType == 'pivotColumnGroup') { return `PC: ${defaultHeaderName}`; } return defaultHeaderName; }, }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Table Layout', Layouts: [ { Name: 'Table Layout', TableColumns: [ 'name', 'language', 'github_stars', 'license', 'updated_at', 'has_wiki', 'created_at', 'pushed_at', 'github_watchers', ], ColumnSizing: { name: {Width: 150}, }, }, { Name: 'Row Grouped Layout', RowGroupedColumns: ['license'], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', ], }, { Name: 'Column Group Layout', TableColumns: [ 'name', 'language', 'open_issues_count', 'closed_issues_count', 'github_stars', 'license', 'updated_at', 'has_wiki', 'created_at', 'pushed_at', 'github_watchers', ], }, { Name: 'Pivot Layout', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ {ColumnId: 'github_watchers', AggFunc: 'sum'}, {ColumnId: 'github_stars', AggFunc: 'sum'}, ], SuppressAggFuncInHeader: true, }, ], }, }, }; ``` ```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, wrapHeaderText: true, autoHeaderHeight: true, }, columnDefs: columnDefs, rowData: rowData, sideBar: true, }; ``` ```ts import {ColDef, ColGroupDef} from 'ag-grid-enterprise'; export const columnDefs: (ColDef | ColGroupDef)[] = [ { field: 'id', cellDataType: 'number', hide: true, editable: false, }, { field: 'name', cellDataType: 'text', }, { headerName: 'Issues', marryChildren: true, children: [ { field: 'open_issues_count', headerName: 'Open Issues', cellDataType: 'number', // columnGroupShow: 'closed', }, { field: 'closed_issues_count', headerName: 'Closed Issues', cellDataType: 'number', // columnGroupShow: 'closed', }, ], }, { field: 'language', cellDataType: 'text', enablePivot: true, enableRowGroup: true, }, { field: 'created_at', headerName: 'Created', cellDataType: 'date', }, { field: 'updated_at', headerName: 'Updated', cellDataType: 'date', }, { field: 'pushed_at', headerName: 'Pushed', cellDataType: 'date', }, { field: 'description', cellDataType: 'text', sortable: false, 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: 'github_stars', headerName: 'GitHub Stars', cellDataType: 'number', enableValue: true, }, { field: 'github_watchers', headerName: 'GitHub Watchers', cellDataType: 'number', enableValue: true, }, { field: 'week_issue_change', headerName: 'Issue Change', cellDataType: 'number', enableValue: true, }, ]; ``` --- # Managing Columns in UI Canonical page: https://www.adaptabletools.com/docs/dev-guide-columns-column-info - The Column Info Panel contains at a glance information about each Column Managing and monitoring Columns in AdapTable is done in the Column Info Panel. ## Column Info Panel The Column Info Panel is in the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md) (the 2nd panel displayed by default) - Column Info can also be opened via the `Column Info` Menu Option in 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 `Grid Info` which opens the [Grid Info Panel](https://www.adaptabletools.com/docs/dev-guide-support-monitoring/index.md) The Column Info Panel contains a dropdown listing all the Columns in the Grid. When a Column is selected, the Panel displays all the information about the Column in 2 tabs: - Column Summary - State ### Column Summary The Column Summary tab provides basic information about the selected Column. This includes: - Column Id - Column Header - Column DataType - Other Column properties - e.g. Aggregatable, Filterable, Editable, Queryable, Sortable, Moveable etc ### Column State Th Column State tab displays information about every [Adaptable Object](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects) related to the selected column. It also contains buttons to edit / delete these Objects via the relevant [Wizard](https://www.adaptabletools.com/docs/ui-settings-panel-wizards/index.md). **Example: Column Info Panel** Using Column Info to see details about specific Columns - This demo illustrates the Column Info section of the Settings Panel ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Column 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.columnApi.openColumnInfoSettingsPanel(); }; ``` --- # Providing Column Types Canonical page: https://www.adaptabletools.com/docs/dev-guide-columns-column-types - Column Types are provided by Developers using the `type` property in the AG Grid Column Def - They are leveraged by AdapTable, in particular, for 4 important use cases: - To define Scope so that all Columns which share a type are treated as a group (i.e. given a Column Format) - Identify "special" (e.g. Calculated, FreeText and Action) Columns so AG Grid properties can be applied - To hide a Column so it is never visible in the Grid - To create Pivot Total Columns Column Types are supplied via the `type` property in an AG Grid Column Schema definition. - The `type` property accepts an array as well as a single value - This allows developers to provide their own types as well as those which AdapTable and / or AG Grid expect There are 2 main use cases where Column Types are used in AdapTable. ## Column Type Scope Column Types can be used as an option when defining [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md). This commonly used object sets which Columns are to be included in an AdapTable Object (e.g. [Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md), [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md), [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) and other objects). All columns containing the specified Column Type will be **dynamically** included in the Object's Scope. - Column Types are **not** automatically available for AdapTable run-time users in the UI and associated wizards - Use the `columnTypes` property in [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) to specify which of the supplied Column Types are listed ### `columnTypes` Optional list of Column Types - used when defining Scope in AdapTable UI & decorating Special Columns This property in [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) returns a list containing the subset of Column Types which have been defined in AG Grid column definitions, that should be made available to run-time AdapTable users. This is particularly useful when defining [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) - via the object's `Scope` property - for a group of Columns. It is defined as follows: ```ts columnTypes?: string[] | ((context: ColumnTypesContext) => string[]); ``` As can be seen the list can be provided in 2 ways: - via hard-coded array of strings - using a function which receives a [`ColumnTypesContext`](https://www.adaptabletools.com/docs/reference/columntypescontext.md) object and returns an arrray of strings - When defining the Scope in a Wizard, only the items returned by this property are visible to the run-time user - Values returned in this property **must exist** in at least one `Type` property in an AG Grid column definition ```ts {4} // Define 4 Column Types via a list const adaptableOptions: AdaptableOptions = { columnOptions: { columnTypes: ['number-column', 'price', 'user', 'decimal'] } ``` ```ts {4} // Define 4 Column Types using a Function const adaptableOptions: AdaptableOptions = { columnOptions: { columnTypes: (context: ColumnTypesContext) => ['number-column', 'price', 'user', 'decimal'] } ``` This can then be put together with objects as follows: ```ts {4,11,18,26} // Define 3 Column Types and reference them in Format Columns const adaptableOptions: AdaptableOptions = { columnOptions: { columnTypes: ['number-column', 'price', 'user', 'decimal'] } initialState : { FormatColumn: { FormatColumns: [ { Name: 'format-number-center', Scope: { ColumnTypes: ['number-column'] }, Style: { Alignment: 'Center', }, }, { Name: 'format-price-four-digits', Scope: { ColumnTypes: ['price'] }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { FractionDigits: 4 }, }, }, { Name: 'format-user-back-colour', Scope: { ColumnTypes: ['user'] }, Style: { BackColor: '#00ffff', ForeColor: 'Black' }, }, ], }, }; } ``` **Example: Column Type Scope** Column Scope in Format Columns - This demo showcases how to use Column Type Scope, through 3 [Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md): - The 2 Columns with a type of `github` (i.e. `Github Watchers` & `Github Stars`) have a style of bold and centre-aligned - The 4 Columns with a type of `issue-pr` (i.e. `Open Issues`, `Closed Issues`, `Open PRs` & `Closed PRs`) have a style of black font on blue background - The 2 Calculated Columns (and therefore with a type of `calculatedColumn` - `githubPopularity` & `totalStars`) have a style of pink font and bold - The 3 types have also been provided in the `columnTypes` property in [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) so they can be accessed in the UI ```ts import {AdaptableOptions, AdaptableColumnType} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Column Type Scope', columnOptions: { columnTypes: ['github', 'issue-pr', AdaptableColumnType.CalculatedColumn], }, initialState: { Dashboard: {ModuleButtons: ['FormatColumn', 'SettingsPanel']}, Theme: {CurrentTheme: 'dark'}, CalculatedColumn: { CalculatedColumns: [ { FriendlyName: 'Popularity', ColumnId: 'githubPopularity', Query: { ScalarExpression: '[github_watchers] + [github_stars]', }, CalculatedColumnSettings: { DataType: 'number', }, }, { ColumnId: 'totalStars', FriendlyName: 'Total Stars', Query: { AggregatedScalarExpression: 'Sum([github_stars])', }, CalculatedColumnSettings: { DataType: 'number', }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-github', Scope: { ColumnTypes: ['github'], }, Style: { FontWeight: 'Bold', Alignment: 'Center', }, }, { Name: 'formatColumn-issue-pr', Scope: { ColumnTypes: ['issue-pr'], }, Style: { BackColor: '#8fd3fe', ForeColor: 'Black', }, }, { Name: 'formatColumn-CalculatedColumn', Scope: { ColumnTypes: [AdaptableColumnType.CalculatedColumn], }, Style: { ForeColor: 'Pink', FontStyle: 'Italic', }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_watchers', 'github_stars', 'open_issues_count', 'closed_issues_count', 'githubPopularity', 'totalStars', 'open_pr_count', 'closed_pr_count', 'license', 'week_issue_change', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'has_projects', 'has_pages', ], AutoSizeColumns: true, }, ], }, }, }; ``` ## AdapTable Column Types AdapTable leverages Column Types in 4 main use cases. - Dealing with **Special Columns**, ie. [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 - When **enhancing Pivoting** by using [Pivot Total Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md) - When **hiding Columns** so they are not [visible in the UI to users](https://www.adaptabletools.com/docs/dev-guide-columns-hiding-columns/index.md) - When **using FDC3** by enabling special [FDC3 Columns](https://www.adaptabletools.com/docs/handbook-fdc3/index.md) There are, currently, 9 column type values provided by AdapTable: - AdapTable helps developers to configure the correct `type` property via Intellisense - This is done via the `AdaptableColumnType` object enabling, for example: ```ts{2} Scope: { ColumnTypes: [AdaptableColumnType.CalculatedColumn] // instead of 'calculatedColumn' }, ``` | String Equivalent | AdaptableColumnType Value | | ----------------------- | ------------------------- | | `actionColumn` | ActionColumn | | `calculatedColumn` | CalculatedColumn | | `fdc3Column` | Fdc3Column | | `freeTextColumn` | FreeTextColumn | | `hiddenColumn` | HiddenColumn | | `pivotAnyTotal` | PivotAnyTotal | | `pivotGrandTotal` | PivotGrandTotal | | `pivotColumnTotal` | PivotColumnTotal | | `pivotAggregationTotal` | PivotAggregationTotal | ### Special Columns The most common use case for using Column Types in AdapTable is when configuring Special Columns: - [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - [FreeText Columns](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) - [Action Columns](https://www.adaptabletools.com/docs/handbook-action-column/index.md) Column Types are used here in 2 separate use cases: - updating AG Grid Definitions - providing additional column properties #### AG Grid Definitions Sometimes the developer might wish to refer to an AdapTable Special Column when creating Column Schema Definitions in AG Grid `Grid Options`. - This can be useful if you want to place the Column in a [Column Group](https://www.adaptabletools.com/docs/handbook-grouping-columns/index.md) - Or if you want to add an AG Grid specific column definition property (e.g. a custom Tooltip component) AG Grid Columns which will also serve as Special Columns are marked by configuring the `types` property of the Column Definition as follows: | Special Column | Value for `type` property | | --------------------------------------------------------------------------- | ------------------------- | | [Action Columns](https://www.adaptabletools.com/docs/handbook-action-column/index.md) | `actionColumn` | | [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) | `calculatedColumn` | | [FreeText Columns](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) | `freeTextColumn` | - By default, AdapTable creates a new AG Grid column for each Special Column it encounters - But in this scenario, it will **update** (patch) the AG Grid column with extra properties as required ### Defining Special Columns in AG Grid There are 3 main steps you **must** follow in order to wire up AdapTable Special Columns in AG Grid: Use a full Column Definition as normal. Add the ColDef to a Column Group if required. Provide any components (e.g. Tooltip) as needed. The `colId` value should be the same as that used for `ColumnId` in the Special Column definition ```tsx [[1, 8, "subscribersRatio"], [1, 17, "comments"]] export const columnDefs: (ColDef | ColGroupDef)[] = [ { groupId: 'demoColGroup', headerName: 'Special Columns', children: [ { // Create a Calculated Column colId: 'subscribersRatio', // has to be same Id as in InitialState cellDataType: 'number', type: [AdaptableColumnType.CalculatedColumn, 'number-cell'], // add a tooltip if required tooltipValueGetter: (params: ITooltipParams) => params.data, tooltipComponent: CustomTooltip, }, { // Create a Free Text Column colId: 'comments', // has to be same Id as in InitialState cellDataType: 'text', type: 'AdaptableColumnType.FreeTextColumn', headerTooltip: 'Sometimes high, sometimes low', }, ], }, ]; ``` Make sure to add correct value to the `type` property. This should be: - `calculatedColumn` - for Calculated Columns - `freeTextColumn` - for FreeText Columns ```tsx [[2, 10, "AdaptableColumnType.CalculatedColumn"], [2, 19, "AdaptableColumnType.FreeTextColumn"]] export const columnDefs: (ColDef | ColGroupDef)[] = [ { groupId: 'demoColGroup', headerName: 'Special Columns', children: [ { // Create a Calculated Column colId: 'subscribersRatio', // has to be same Id as in InitialState cellDataType: 'number', type: ['AdaptableColumnType.CalculatedColumn', 'number-cell'], // add a tooltip if required tooltipValueGetter: (params: ITooltipParams) => params.data, tooltipComponent: CustomTooltip, }, { // Create a Free Text Column colId: 'comments', cellDataType: 'text', type: 'AdaptableColumnType.FreeTextColumn', headerTooltip: 'Sometimes high, sometimes low', }, ], }, ]; ``` Define the Special Columns normally. AdapTable will then automatically wire up the columns to the exsting AG Grid columns. This will be done in place of the usual pratice which is to create a new AG Grid column. ```tsx [[3, 5, "subscribersRatio"], [3, 18, "comments"]] CalculatedColumn: { CalculatedColumns: [ { FriendlyName: 'Subscribers Ratio', ColumnId: 'subscribersRatio', Query: { ScalarExpression: '[github_stars] / [github_watchers]', }, CalculatedColumnSettings: { DataType: 'number', }, }, ], }, FreeTextColumn: { FreeTextColumns: [ { ColumnId: 'comments', FreeTextColumnSettings: { DataType: 'text', }, }, ], }, ``` **Example: Special Column Types** Defining 'Special Column' Types in AG Grid - This demo shows 2 Special Columns that have been predefined in AG Grid: - Calculated Column - `Subscribers Ratio` - Free Text Column - `Comments` - Both Columns have been predefined in AG Grid with these features: - Placed in a Column Group (called Special Columns) - A (cell) Tooltip has been added to the `Subscribers Ratio` column - A Header Tooltip has been added to the `Comments` column - Both Columns have been created in Initial Adaptable State - using **same** value for AG Grid `colID` and AdapTable `ColumnId` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'AG Grid Defined Special Columns', initialState: { Dashboard: { ModuleButtons: ['CalculatedColumn', 'FreeTextColumn', 'SettingsPanel'], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'github_watchers', 'subscribersRatio', 'comments', ], Name: 'Standard Layout', }, ], }, CalculatedColumn: { CalculatedColumns: [ { FriendlyName: 'Subscribers Ratio', ColumnId: 'subscribersRatio', Query: { ScalarExpression: '[github_stars] / [github_watchers]', }, CalculatedColumnSettings: { DataType: 'number', }, }, ], }, FreeTextColumn: { FreeTextColumns: [ { ColumnId: 'comments', FriendlyName: 'Comments', FreeTextStoredValues: [ {PrimaryKey: 24195339, FreeText: 'Used by the US team'}, {PrimaryKey: 224663696, FreeText: 'My personal favourite'}, {PrimaryKey: 82095231, FreeText: 'Required by Support Team'}, ], FreeTextColumnSettings: { Aggregatable: false, DataType: 'text', }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-subscribersRatio', Scope: { ColumnIds: ['subscribersRatio'], }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { FractionDigits: 2, Suffix: '%', }, }, }, ], }, }, }; ``` ```ts import { ColDef, ColGroupDef, ITooltipComp, ITooltipParams, } from 'ag-grid-enterprise'; import {AdaptableColumnType} from '@adaptabletools/adaptable'; class CustomTooltip implements ITooltipComp { eGui: any; init(params: ITooltipParams & {color: string; backgroundColor: string}) { const eGui = (this.eGui = document.createElement('div')); const color = params.color || 'black'; const backgroundColor = params.backgroundColor || 'white'; const githubstarscount = params.data['github_stars']; const githubwatcherscount = params.data['github_watchers']; //@ts-ignore eGui.style['color'] = color; //@ts-ignore eGui.style['background-color'] = backgroundColor; eGui.style['border'] = '1px solid gray'; eGui.innerHTML = `

Stars: ${githubstarscount}
Watchers ${githubwatcherscount}

`; } 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. ![AdapTable shows up in Chrome DevTools Performance Profiler tracks](https://www.adaptabletools.com/images/custom-dev-tracks.png) 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} ``` - [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 => item !== '-' ) .filter( item => item.category === 'Comment' || item.category === 'Note' ); }, }, commentOptions: { loadCommentThreads: async (commentLoadContext: CommentLoadContext) => { commentsService.subscribeToComments(comments => { commentLoadContext.adaptableApi.commentApi.setComments(comments); }); return commentsService.getComments(); }, persistCommentThreads: async (commentThreads: CommentThread[]) => { commentsService.setComments(commentThreads); }, }, 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, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; export const onAdaptableReady = (adaptableReadyInfo: AdaptableReadyInfo) => { adaptableReadyInfo.adaptableApi.commentApi.clearComments(); setTimeout(() => { adaptableReadyInfo.adaptableApi.commentApi.addComment( 'Does anyone know this Stencil license?', { ColumnId: 'license', PrimaryKeyValue: 82095231, } ); adaptableReadyInfo.adaptableApi.commentApi.addComment( 'Does anyone know this Polymer license?', { ColumnId: 'license', PrimaryKeyValue: 5532320, } ); }, 100); }; ``` ```css /* Custom Variables */ /* Overriding the dark theme */ :root.ab--theme-dark { --ab-CellComment-triangle-color: yellow; } ``` ## Timestamp Date Format AdapTable provides a property to configure how the timestamp of a Comment is displayed. This is used in both the Comment itself and the Commments screen that shows all current Comments The property is available in [Comment Options](https://www.adaptabletools.com/docs/handbook-comments-technical-reference/index.md) and returns a string (optionally via a function). ### `dateFormat` Date Format to use for timestamp in Comments By default AdapTable will format the timestamp using 'dd-MM-yyyy HH:mm:ss'. Use this property to set an alternative Date Format, including via a function if preferred. ```ts {3} // Provide custom Date Format commentOptions:{ dateFormat: 'MMM do yyyy', }; ``` **Example: Comments Date Format** Configuring the format for Comments timestamp - In this demo we provide a custom Date Format of 'MMM do yyyy' which is used when displaying the Timestamp in Comments ```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: 'Comments Date Format', userName: 'Demo User', contextMenuOptions: { customContextMenu: (customMenuContext: CustomContextMenuContext) => { return customMenuContext.defaultAdaptableMenuStructure .filter( ( item ): item is AdaptableSystemContextMenuItem => item !== '-' ) .filter( item => item.category === 'Comment' || item.category === 'Note' ); }, }, commentOptions: { loadCommentThreads: async (commentLoadContext: CommentLoadContext) => { commentsService.subscribeToComments(comments => { commentLoadContext.adaptableApi.commentApi.setComments(comments); }); return commentsService.getComments(); }, persistCommentThreads: async (commentThreads: CommentThread[]) => { commentsService.setComments(commentThreads); }, dateFormat: 'MMM do yyyy', }, 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, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; export const onAdaptableReady = (adaptableReadyInfo: AdaptableReadyInfo) => { adaptableReadyInfo.adaptableApi.commentApi.clearComments(); setTimeout(() => { adaptableReadyInfo.adaptableApi.commentApi.addComment( 'Does anyone know this Stencil license?', { ColumnId: 'license', PrimaryKeyValue: 82095231, } ); adaptableReadyInfo.adaptableApi.commentApi.addComment( 'Does anyone know this Polymer license?', { ColumnId: 'license', PrimaryKeyValue: 5532320, } ); }, 100); }; ``` ## Viewing Comments By default run-time users will see a Comment when the mouse hovers over a cell containing a note. If this is not wanted (e.g. the user gets irritated by the hover) AdapTable offers another way to view a Comment. You can right-click the containing cell and choose the `Show Comment` menu option in the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md). **Example: Comments Menu** Viewing Comments via Context Menu - In this demo we have set Comments to be viewed in the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) instead of the default mouse hover ```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: 'Viewing Comments via Context Menu', userName: 'Demo User', commentOptions: { showCommentAction: 'menu', loadCommentThreads: async (commentLoadContext: CommentLoadContext) => { commentsService.subscribeToComments(comments => { commentLoadContext.adaptableApi.commentApi.setComments(comments); }); return commentsService.getComments(); }, persistCommentThreads: async (commentThreads: CommentThread[]) => { commentsService.setComments(commentThreads); }, }, 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, }, ], }, }, }; ``` --- # Comments Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-comments-technical-reference - Comment Options allows developers to configure which Cells can receive Comments - Comment API provides run time access to Comments ------------- ## Comment State There is no Comment State due to the collaborative nature of comments. Instead Comment Threads are stored using the functions provided in Comment Options. ------------- ## Comment Options The [`Comment Options`](https://www.adaptabletools.com/docs/reference/commentoptions.md) section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) contains properties used to configure Comments: | Property | Type | Description | Default | | --- | --- | --- | --- | | [dateFormat](https://www.adaptabletools.com/docs/reference/commentoptions.md#dateformat) | `string \| (() => string)` | Date Format string for Comments timestamp | 'dd-MM-yyyy HH:mm:ss' | | [isCellCommentable](https://www.adaptabletools.com/docs/reference/commentoptions.md#iscellcommentable) | `(commentableCellContext: `[`CommentableCellContext`](https://www.adaptabletools.com/docs/reference/commentablecellcontext.md)`) => boolean` | Function to configure if a cell can contain Comments | | | [showCommentAction](https://www.adaptabletools.com/docs/reference/commentoptions.md#showcommentaction) | `'hover' \| 'menu'` | Whether to show Comments by hovering (default) or via context menu | 'hover' | | [showPopupCloseButton](https://www.adaptabletools.com/docs/reference/commentoptions.md#showpopupclosebutton) | `boolean` | Show the Close Button in the Comments Popup | true | ### Loading and Saving Comments Comment Options contains 2 functions which developers must provide in order to load and save Comments: | Method | Returns | Description | | --- | --- | --- | | [loadCommentThreads(commentLoadContext)](https://www.adaptabletools.com/docs/reference/commentoptions.md#loadcommentthreads) | `Promise<`[`CommentThread`](https://www.adaptabletools.com/docs/reference/commentthread.md)`[]>` | Loads the Comment Threads | | [persistCommentThreads(commentThreads)](https://www.adaptabletools.com/docs/reference/commentoptions.md#persistcommentthreads) | `Promise` | Persists the current Comment Threads | ------------- ## Comment Changed Event The Comment Changed Event fires whenever a Comment changes. ### CommentChangedInfo The event comprises a single [`CommentChangeInfo`](https://www.adaptabletools.com/docs/reference/commentchangedinfo.md) object which provides all the current Comment Threads. | Property | Type | Description | | --- | --- | --- | | [commentThreads](https://www.adaptabletools.com/docs/reference/commentchangedinfo.md#commentthreads) | [`CommentThread`](https://www.adaptabletools.com/docs/reference/commentthread.md)`[]` | All current Comment Threads | | [adaptableContext](https://www.adaptabletools.com/docs/reference/commentchangedinfo.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('CommentChanged', (eventInfo: CommentChangedInfo) => { // do something with the info }); ``` ------------- ## Comment API Full programmatic access to Comments is available in [`Comment API`](https://www.adaptabletools.com/docs/reference/commentapi.md) section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md). | Method | Returns | Description | | --- | --- | --- | | [addComment(commentText, cellAddress)](https://www.adaptabletools.com/docs/reference/commentapi.md#addcomment) | `void` | Add a Comment to a Comment Thread | | [addCommentThread(commentThread)](https://www.adaptabletools.com/docs/reference/commentapi.md#addcommentthread) | `void` | Create a new Comment Thread | | [clearComments()](https://www.adaptabletools.com/docs/reference/commentapi.md#clearcomments) | `void` | Clear all Comment Threads in the grid | | [deleteComment(comment, cellAddress)](https://www.adaptabletools.com/docs/reference/commentapi.md#deletecomment) | `void` | Delete a Comment | | [deleteCommentThread(cellAddress)](https://www.adaptabletools.com/docs/reference/commentapi.md#deletecommentthread) | `void` | Delete all Comments for a particular cell | | [editComment(comment, cellAddress)](https://www.adaptabletools.com/docs/reference/commentapi.md#editcomment) | `void` | Edit a Comment | | [getAllComments()](https://www.adaptabletools.com/docs/reference/commentapi.md#getallcomments) | [`CommentThread`](https://www.adaptabletools.com/docs/reference/commentthread.md)`[]` | Return all Comment Threads in the grid | | [getCommentThreadForCell(cellAddress)](https://www.adaptabletools.com/docs/reference/commentapi.md#getcommentthreadforcell) | [`CommentThread`](https://www.adaptabletools.com/docs/reference/commentthread.md)` \| undefined` | Return the Comment Thread for a particular cell | | [hideCommentsPopup()](https://www.adaptabletools.com/docs/reference/commentapi.md#hidecommentspopup) | `void` | Close the Comment Popup | | [setComments(commentThreads)](https://www.adaptabletools.com/docs/reference/commentapi.md#setcomments) | `void` | Sets the Comment Threads in the grid | --- # Conditional Styling Canonical page: https://www.adaptabletools.com/docs/handbook-conditional-styling - This AdapTable Help Page has been moved - Since [Adaptable Version 13](https://www.adaptabletools.com/support/version-13-release-note) Conditions are now contained in [Column Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) - See [Column Formatting Conditions](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) for more information --- # Custom Columns Canonical page: https://www.adaptabletools.com/docs/handbook-custom-columns --- # Sorting Canonical page: https://www.adaptabletools.com/docs/handbook-custom-sorting - Column Sorting in AdapTable is configured through Layouts which contain full sorting information - Additionaly AdapTable offers Custom Sorting whereby a bespoke sort order can be provided for a Column - Custom Sorts can be supplied in 2 ways: - as a hard coded list in Initial Adaptable State - a function supplied in Adaptable Options AdapTable fully supports sorting of your data in AG Grid. ## Column Sorting Column Sorting is managed through [Layouts Sorting](https://www.adaptabletools.com/docs/handbook-layouts-table-sorting/index.md). Each Layout includes a `ColumnSorts` which contains details of which Columns are sorted and in which order. Like all Layout props this can be predefined, allowing developers to define the sorted columns when the Layout loads ## Custom Sorting Custom Sorting enables [Adaptable Columns](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) to be given a bespoke sort order. This will be applied by AdapTable whenever the column is sorted in place of the column's default sort order. Custom Sorts are applied when a Column is sorted in AG Grid in both table and pivot Layouts Custom Sorting is useful when the contents of a column are typically ordered in an non-standard way. ### Default Sorting Rules for each Column DataType The default sort order in AG Grid for each data type is: | Column Data Type | Rule | | ---------------- | ------------------ | | String | Alphabetical Order | | Number | Highest to Lowest | | Date | Oldest to Newest | This is what is used when a Column is sorted in the absence of Custom Sorting For example, a 'Ratings' column can be sorted by rating (i.e. 'AAA', 'AA1' etc) rather than alphabetically (the default for string columns). A Custom Sort can be one of 2 types: - **Hard-coded List** of Values - provided in [Custom Sort Initial State](https://www.adaptabletools.com/docs/handbook-custom-sorting-technical-reference/index.md) (or via the UI) - **Comparer** function - provided in [Custom Sort Options](https://www.adaptabletools.com/docs/handbook-custom-sorting-technical-reference/index.md), invoked by AdapTable each time the column's sorted - Only one Custom Sort can be supplied per Column - Custom Sort Comparers **take precedence** over Hard-coded Lists ## Defining Custom Sorts At design time developers can configure both types of Custom Sorts. ### Hardcoded Values Custom Sorts can be provided using a list of values in the [Custom Sort](https://www.adaptabletools.com/docs/handbook-custom-sorting-technical-reference/index.md) section of Initial Adaptable State. AdapTable will sort the Column according to the order of the supplied values. - Its likely the Column will contain values that are not included in the Custom Sort implementation list - AdapTable will sort them according to the default alphabetic order ### Defining a Custom Sort with Hardcoded Values Add a `CustomSort` section containing an array of [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md) objects. Choose a unique name for the Custom Sort Specify the Id of Column which will use the Custom Sort Supply an ordered list by which the column will be sorted Values not provided are sorted using Column's default sort order ```js [[1, 2, "CustomSort"],[1, 3, "CustomSorts"],[2, 5, "Name"],[3, 6, "ColumnId"], [4, 7, "SortedValues"]] const initialState: InitialState = { CustomSort: { CustomSorts: [ { Name: 'CustomSort-Rating', ColumnId: 'Rating', SortedValues: ['AAA', 'AA+', 'AA', 'AA-'], // etc. }, ], }, } as InitialState; ``` **Example: Custom Sorts: Values** Providing Custom Sort Initial State - This demo illustrates 2 Columns that contain Custom Sorts which provide a list of Values (and for each we add a Column Sort to the [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md)): - `License` - orders using `Other` as first cell value - `Language` - orders as 'TypeScript', 'JavaScript', 'HTML' ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom Sort Values', initialState: { Dashboard: { ModuleButtons: ['CustomSort', 'SettingsPanel'], }, CustomSort: { CustomSorts: [ { Name: 'customSort-license', ColumnId: 'license', SortedValues: ['Other'], }, { Name: 'customSort-language', ColumnId: 'language', SortedValues: ['TypeScript', 'JavaScript'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', ColumnSorts: [ { ColumnId: 'license', SortOrder: 'Asc', }, { ColumnId: 'language', SortOrder: 'Asc', }, ], TableColumns: [ 'name', 'license', 'language', 'week_issue_change', '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, }, ], }, }, }; ``` ### Comparer Function For more complicated scenarios a `customSortComparer` function can be supplied by developers. This comparer function will be invoked by AdapTable each time the Column is sorted. Comparer functions are provided in the `customSortComparers` property of [Custom Sort Options](https://www.adaptabletools.com/docs/handbook-custom-sorting-technical-reference/index.md). ### `customSortComparers` Custom Sort Column Comparer Functions [`ColumnValuesComparer[]`](https://www.adaptabletools.com/docs/reference/columnvaluescomparer.md) Functions used to compare Columns whem implementing Custom Sort. As there can be only one Sort Order for a Column, implementations provided here **take precedence** over those given as a hardcoded list in Initial Adaptable State The function returns a `ColumnValuesComparer` object which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [comparer](https://www.adaptabletools.com/docs/reference/columnvaluescomparer.md#comparer) | [`AdaptableComparerFunction`](https://www.adaptabletools.com/docs/reference/adaptablecomparerfunction.md)`` | Comparer function to use | | [name](https://www.adaptabletools.com/docs/reference/columnvaluescomparer.md#name) | `string` | Name of the CustomSort Comparer | | [scope](https://www.adaptabletools.com/docs/reference/columnvaluescomparer.md#scope) | [`ColumnScope`](https://www.adaptabletools.com/docs/reference/columnscope.md) | Column for which to compare values | The `scope` property is of type [`ColumnScope`](https://www.adaptabletools.com/docs/reference/columnscope.md) which is [commonly used across AdapTable](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md). The `comparer` property is of type [`AdaptableComparerFunction`](https://www.adaptabletools.com/docs/reference/adaptablecomparerfunction.md) which is defined as follows: ```ts /** * Standard comparer function used to evaluate custom sorts * should return -1, 0, 1 as required * valueA and valueB are first and second cell to compare * nodeA and nodeB are first and second rows to compare */ export type AdaptableComparerFunction = ( valueA: any, valueB: any, nodeA: IRowNode, nodeB: IRowNode ) => number; ``` The Comparer can be used like this: ```ts {4} // Compare Issue Change by size of change (ignoring negatives) const adaptableOptions: AdaptableOptions = { customSortOptions : { customSortComparers: [ { name: 'absolute_custom_sort', scope: { ColumnIds: ['week_issue_change'] }, comparer: (valueA: any, valueB: any, nodeA?: IRowNode, nodeB?: IRowNode) => { return Math.abs(valueB) - Math.abs(valueA); }, }: ], }; }; ``` - Unlike with Hardcoded Values the `customSortComparer` function can be given [Column Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) - This allows, for example, for a single `customSortComparer` function to be provided for all Date columns ### Defining a Custom Sort using a CustomSortComparer function Just a few steps are required to define a Custom Sort Comparer. In this example, we provide a Comparer which will ignore negatives and sort by absolute value Add `customSortComparers` property to Custom Sort Options Provide a unique name for the Comparer The commonly-used [Column Scope object](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) defines where the Custom Sort Comparer will run. It can be: - One or more ColumnIds - A [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) (e.g. text, date, number) - A [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) The function receives 2 cell values (and their containing row nodes) The evaluation returns -1, 1 or 0 based on comparison being made ```ts [[1, 3, "customSortComparers"],[2, 5, "name"],[3, 6, "scope"],[4, 9, "comparer"]] // Sort Issue Change by size of change (ignoring negatives) customSortOptions : { customSortComparers: [ { name: 'absolute_sort', scope: { DataTypes: ['number'] }, comparer: (valA: any, valB: any: IRowNode) => { return Math.abs(valB) - Math.abs(valA); }, }: ] }; ``` **Example: Custom Sorts: Functions** Providing Custom Sort Functions - This demo contains 3 Columns with Custom Sorts provided via a `customSortComparer` Function: - `Issue Change` - the `customSortComparer` negates the numbers to order changes by size (we sort on this by default in the [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md)) - `Name` - the `customSortComparer` orders the column according to the value in the `GitHub Stars` column - `Rating` - the `customSortComparer` uses the `localeCompare` function (so it orders a, A, b, B, c, C etc) - Sort on the `Name` column to see how its sorted according to the `GitHub Stars` column value - Sort on the `Rating` column to see how the comparer function sorts ignoring case ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {IRowNode} from 'ag-grid-enterprise'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom Sort Functions', customSortOptions: { customSortComparers: [ { name: 'absolute_sort', scope: { ColumnIds: ['week_issue_change'], }, comparer: (valueA: any, valueB: any) => { return Math.abs(valueB) - Math.abs(valueA); }, }, { name: 'rating_sort', scope: { ColumnIds: ['rating'], }, comparer: (valueA: any, valueB: any) => { return valueA.localeCompare(valueB); }, }, { name: 'name_sort', scope: { ColumnIds: ['name'], }, comparer: ( valueA: any, valueB: any, nodeA: IRowNode | undefined, nodeB: IRowNode | undefined ) => { const nodeAGitHubStars = nodeA?.data['github_stars']; const nodeBGitHubStars = nodeB?.data['github_stars']; if (nodeAGitHubStars > nodeBGitHubStars) { return -1; } if (nodeAGitHubStars < nodeBGitHubStars) { return 1; } return 0; }, }, ], }, initialState: { Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', ColumnSorts: [ { ColumnId: 'week_issue_change', SortOrder: 'Asc', }, ], TableColumns: [ 'name', 'github_stars', 'rating', 'week_issue_change', '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, }, ], }, }, }; ``` ```ts export interface WebFramework { id: number; name: string; full_name?: string; html_url?: string; rating: 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', rating: 'A', 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', rating: 'a', 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', rating: 'B', 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', rating: 'C', 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, }, { id: 224663696, name: 'alpine', full_name: 'alpinejs/alpine', html_url: 'https://github.com/alpinejs/alpine', rating: 'A', 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', rating: 'b', 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', rating: 'b', 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, }, { id: 1801829, name: 'ember.js', full_name: 'emberjs/ember.js', html_url: 'https://github.com/emberjs/ember.js', rating: 'c', 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', rating: 'C', 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', rating: 'B', 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, }, { id: 17814354, name: 'mithril.js', full_name: 'MithrilJS/mithril.js', html_url: 'https://github.com/MithrilJS/mithril.js', rating: 'a', 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', rating: 'B', 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', rating: 'a', 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', rating: 'C', 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', rating: 'c', 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: 191051391, name: 'redwood', full_name: 'redwoodjs/redwood', html_url: 'https://github.com/redwoodjs/redwood', rating: 'b', 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, }, { id: 36040894, name: 'gatsby', full_name: 'gatsbyjs/gatsby', html_url: 'https://github.com/gatsbyjs/gatsby', rating: 'a', 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', rating: 'A', 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: 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', rating: 'B', 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', rating: 'b', 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: 121594173, name: 'aurelia', full_name: 'aurelia/aurelia', html_url: 'https://github.com/aurelia/aurelia', rating: 'c', 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: 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', rating: 'C', 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', rating: 'A', 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', rating: 'B', 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', rating: 'a', 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 {WebFramework} from './rowData'; export const columnDefs: ColDef[] = [ { field: 'name', cellDataType: 'text', sortable: true, }, { field: 'language', cellDataType: 'text', enablePivot: true, enableRowGroup: true, }, { field: 'github_stars', headerName: 'GitHub Stars', cellDataType: 'number', type: 'github', enableValue: true, }, { field: 'github_watchers', headerName: 'GitHub Watchers', cellDataType: 'number', type: 'github', enableValue: true, }, { 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: 'rating', cellDataType: 'text', sortable: true, }, { field: 'open_issues_count', headerName: 'Open Issues', cellDataType: 'number', type: 'issue-pr', enableValue: true, }, { field: 'closed_issues_count', headerName: 'Closed Issues', cellDataType: 'number', type: 'issue-pr', enableValue: true, }, { field: 'open_pr_count', headerName: 'Open PRs', cellDataType: 'number', type: 'issue-pr', enableValue: true, }, { field: 'closed_pr_count', headerName: 'Closed PRs', cellDataType: 'number', type: 'issue-pr', 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, }, ]; ``` ## Using Custom Sorts Run-time users can create, edit, delete, share and suspend Custom Sorts. This is doing using the Custom Sort section of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md). - The AdapTable UI **only** deals with List-based Custom Sorts - Custom Sort Comparers are design-time objects only and not editable, shareable or suspendable at run-time ### Using the Custom Sort Wizard There are just 3 steps involved when creating a Custom Sort Choose a unique name for the Custom Sort AdapTable will list all the Columns for which there is no existing Custom Sort. Select the Column you require. Unlike [Custom Sort Comparers](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md#general-options) which use full [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md), list-based ones are restricted to a single Column AdapTable will list all the **distinct values** for the Column selected in the previous step. Choose the column values you want in your Custom Sort and drag them to order as required. --- # Sorting Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-custom-sorting-technical-reference - Custom Sorting is provided in 2 ways: - Through Custom Sort State (hardcoded values) - Via customSortComparers function in Custom Sort Options - Run-time access to Custom Sorting is via Custom Sort API - Grid API contains more general sorting functions - The Grid Sorted Event fires whenever sorting changes in AG Grid ----------- ## Custom Sort State The [`Custom Sort`](https://www.adaptabletools.com/docs/reference/customsortstate.md) section of Initial Adaptable State contains a list of [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md) objects: ### Custom Sort Object | Property | Type | Description | | --- | --- | --- | | [CustomSorts](https://www.adaptabletools.com/docs/reference/customsortstate.md#customsorts) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md)`[]` | Collection of Custom Sort objects. | A [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md) object contains simply a ColumnId and a list of values to use for the sort: | Property | Type | Description | | --- | --- | --- | | [ColumnId](https://www.adaptabletools.com/docs/reference/customsort.md#columnid) | `string` | Id of Column on which Custom Sort will be applied | | [Name](https://www.adaptabletools.com/docs/reference/customsort.md#name) | `string` | Name of the Custom Sort definition | | [SortedValues](https://www.adaptabletools.com/docs/reference/customsort.md#sortedvalues) | `(string \| number)[]` | Order of values by which Column will be sorted; Date values are persisted as ISO strings ('yyyy-MM-dd') | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/customsort.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | [IsSuspended](https://www.adaptabletools.com/docs/reference/customsort.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object | ----------- ## Custom Sort Options The Custom Sort Options is used to provide Custom Sort Comparers: | Property | Type | Description | | --- | --- | --- | | [customSortComparers](https://www.adaptabletools.com/docs/reference/customsortoptions.md#customsortcomparers) | [`ColumnValuesComparer`](https://www.adaptabletools.com/docs/reference/columnvaluescomparer.md)`[]` | CustomSort column comparer functions | ----------- ## Custom Sort API The Custom Sort API provides comprehensive programmatic access to Custom Sorting. It includes these functions: | Method | Returns | Description | | --- | --- | --- | | [addCustomSort(customSort)](https://www.adaptabletools.com/docs/reference/customsortapi.md#addcustomsort) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md) | Adds a Custom Sort to Custom Sort collection in Adaptable State | | [createCustomSort(params)](https://www.adaptabletools.com/docs/reference/customsortapi.md#createcustomsort) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md) | Creates new Custom Sort based on given values | | [deleteCustomSort(columnId)](https://www.adaptabletools.com/docs/reference/customsortapi.md#deletecustomsort) | `void` | Removes Custom Sort for a given ColumnId | | [editCustomSort(customSort)](https://www.adaptabletools.com/docs/reference/customsortapi.md#editcustomsort) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md) | Edits a Custom Sort | | [editCustomSortValues(columnId, values)](https://www.adaptabletools.com/docs/reference/customsortapi.md#editcustomsortvalues) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md) | Updates existing Custom Sort with new set of Sorted Values | | [getActiveCustomSorts(config)](https://www.adaptabletools.com/docs/reference/customsortapi.md#getactivecustomsorts) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md)`[]` | Retrieves all Custom Sorts that are active (not-suspended) in Adaptable State | | [getCustomSortById(id, config)](https://www.adaptabletools.com/docs/reference/customsortapi.md#getcustomsortbyid) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md) | Retrieves Custom Sort by the technical ID (from `CustomSortState`) | | [getCustomSortByName(name)](https://www.adaptabletools.com/docs/reference/customsortapi.md#getcustomsortbyname) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md)` \| undefined` | Retrieves a Custom Sort by its Name | | [getCustomSortForColumn(columnId)](https://www.adaptabletools.com/docs/reference/customsortapi.md#getcustomsortforcolumn) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md)` \| undefined` | Retrieves Custom Sort from Adaptable State for Column with given ColumnId | | [getCustomSorts(config)](https://www.adaptabletools.com/docs/reference/customsortapi.md#getcustomsorts) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md)`[]` | Retrieves all Custom Sorts in Adaptable State | | [getCustomSortState()](https://www.adaptabletools.com/docs/reference/customsortapi.md#getcustomsortstate) | [`CustomSortState`](https://www.adaptabletools.com/docs/reference/customsortstate.md) | Retrieves Custom Sort section from Adaptable State | | [getLiveCustomSortComparers()](https://www.adaptabletools.com/docs/reference/customsortapi.md#getlivecustomsortcomparers) | [`ColumnValuesComparer`](https://www.adaptabletools.com/docs/reference/columnvaluescomparer.md)`[]` | Returns all Custom Sort Comparers in Custom Sort Options that are currently applied | | [getLiveCustomSorts()](https://www.adaptabletools.com/docs/reference/customsortapi.md#getlivecustomsorts) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md)`[]` | Retrieves all Custom Sorts in Adaptable State that are currently applied | | [getSuspendedCustomSorts(config)](https://www.adaptabletools.com/docs/reference/customsortapi.md#getsuspendedcustomsorts) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md)`[]` | Retrieves all Custom Sorts that are suspended in Adaptable State | | [openCustomSortSettingsPanel()](https://www.adaptabletools.com/docs/reference/customsortapi.md#opencustomsortsettingspanel) | `void` | Opens Settings Panel with Custom Sort section selected and visible | | [suspendAllCustomSort()](https://www.adaptabletools.com/docs/reference/customsortapi.md#suspendallcustomsort) | `void` | Suspends all Custom Sorts | | [suspendCustomSort(customSort)](https://www.adaptabletools.com/docs/reference/customsortapi.md#suspendcustomsort) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md) | Suspends Custom Sort | | [unSuspendAllCustomSort()](https://www.adaptabletools.com/docs/reference/customsortapi.md#unsuspendallcustomsort) | `void` | Activates all suspended Custom Sort | | [unSuspendCustomSort(customSort)](https://www.adaptabletools.com/docs/reference/customsortapi.md#unsuspendcustomsort) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md) | Un-suspends or activates a suspended Custom Sort | ----------- ## Grid Sorted Event AdapTable fires the Grid Sorted Event whenever any column in AdapTable is sorted. It provides information on what is being sorted in AdapTable. This is often used when wanting to [manage expressions on the Server](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md) ### GridSortedInfo The [`GridSortedInfo`](https://www.adaptabletools.com/docs/reference/gridsortedinfo.md) object provided by the event returns a single object: | Property | Type | Description | | --- | --- | --- | | [adaptableSortState](https://www.adaptabletools.com/docs/reference/gridsortedinfo.md#adaptablesortstate) | [`AdaptableSortState`](https://www.adaptabletools.com/docs/reference/adaptablesortstate.md) | Current sort state in the Grid | | [adaptableContext](https://www.adaptabletools.com/docs/reference/gridsortedinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | The [`AdaptableSortState`](https://www.adaptabletools.com/docs/reference/adaptablesortstate.md) object provides information on what is being sorted in AdapTable. | Property | Type | Description | | --- | --- | --- | | [columnSorts](https://www.adaptabletools.com/docs/reference/adaptablesortstate.md#columnsorts) | [`ColumnSort`](https://www.adaptabletools.com/docs/reference/columnsort.md)`[]` | Columns currently being sorted (with direction) | | [customSortComparers](https://www.adaptabletools.com/docs/reference/adaptablesortstate.md#customsortcomparers) | [`ColumnValuesComparer`](https://www.adaptabletools.com/docs/reference/columnvaluescomparer.md)`[]` | Custom Sort Comparers which are currently applied | | [customSorts](https://www.adaptabletools.com/docs/reference/adaptablesortstate.md#customsorts) | [`CustomSort`](https://www.adaptabletools.com/docs/reference/customsort.md)`[]` | Custom Sorts which are currently applied | It contains 2 sections: - Column Sorts active in AG Grid - Custom Sorts which have been provided in Initial State (i.e. not supplied via [Comparers](https://www.adaptabletools.com/docs/handbook-custom-sorting-technical-reference/index.md)) Custom Sorts are always sent even if none are currently active ### 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('GridSorted', (eventInfo: GridSortedInfo) => { // do something with the info }); ``` There are also some sorting-related functions in [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data-technical-reference/index.md#grid-api) --- # Data Set Forms Canonical page: https://www.adaptabletools.com/docs/handbook-data-set-forms - Data Sets are defined in Adaptable Options - Data Set Definitions can include a Form definition to allow the Data Set to be populated based on user choice DataSets can, optionally, include form definitions. These allow users to further 'filter' what data will be returned by the DataSet. Whenever a DataSet with a form definition is selected, AdapTable will dynamically display an [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md). ## Handling Form Submission Unlike with other DataSets, AdapTable doesn't fire the [DataSet Selected Event](https://www.adaptabletools.com/docs/handbook-data-set-technical-reference/index.md) for DataSets that display forms. Instead the data must be provided to AdapTable via a button provided within the form definition. Make sure that your Form includes a button and an implementation for the `onClick` function ### Understanding DataSet Form Buttons onClick The button's `onClick` function receives a [`DataSetFormContext`](https://www.adaptabletools.com/docs/reference/datasetformcontext.md) object which contains a single property: | Property | Type | Description | | --- | --- | --- | | [dataSet](https://www.adaptabletools.com/docs/reference/datasetformcontext.md#dataset) | [`DataSet`](https://www.adaptabletools.com/docs/reference/dataset.md) | The DataSet which triggered the Form | | [adaptableContext](https://www.adaptabletools.com/docs/reference/datasetformcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | This object inherits from the [`FormContext`](https://www.adaptabletools.com/docs/reference/formcontext.md) object which also contains a single property: | Property | Type | Description | | --- | --- | --- | | [formData](https://www.adaptabletools.com/docs/reference/formcontext.md#formdata) | [`AdaptableFormData`](https://www.adaptabletools.com/docs/reference/adaptableformdata.md) | Adaptable Form Data | | [adaptableContext](https://www.adaptabletools.com/docs/reference/formcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | Together that provides details of the DataSet which was selected, and all associated form data. **Example: Using Data Set Forms** Loading Data in AdapTable with Data Sets - In this example we provide 2 DataSets in the `dataSets` property of [Data Set Options](https://www.adaptabletools.com/docs/handbook-data-set-technical-reference/index.md): - `JavaScript` - loads Frameworks where Language is 'JavaScript' - subscribes to [DataSet Selected Event](https://www.adaptabletools.com/docs/handbook-data-set-technical-reference/index.md) and populates AdapTable using the [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md) - is loaded at start-up (by using the `setDataSet` method in [DataSet API](https://www.adaptabletools.com/docs/handbook-data-set-technical-reference/index.md)) - `TypeScript` - loads Frameworks where Language is 'TypeScript' - displays an [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md), allowing users to set additional filters - the **form** contains an 'OK' button which has an `onClick` handler which sends data to AdapTable also using the [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md) ### Expand to see the DataSet (and Form) definitions The 2 DataSets are defined as follows (note that the 'TypeScript' DataSet includes a Form with a Button) ```ts dataSetOptions: { dataSets: [ { name: 'JavaScript', description: 'JavaScript Frameworks', }, { name: 'TypeScript', description: 'TypeScript Frameworks', form: { fields: [ { name: 'hasWiki', label: 'HasWiki', fieldType: 'checkbox', defaultValue: true, }, { name: 'minStars', label: 'Minimum Stars', defaultValue: 10000, fieldType: 'number', }, { name: 'license', label: 'License', fieldType: 'select', defaultValue: 'MIT License', options: [ { label: 'MIT License', value: 'MIT License', }, { label: 'BSD 3-Clause', value: 'BSD 3-Clause', }, { label: 'Other', value: 'Other', }, ], }, ], buttons: [ { label: 'OK', onClick: (button, context: DataSetFormContext) => { let tsFrameworks = rowData.filter( r => r['language'] === 'TypeScript' && r['license'] == context.formData?.license && r['github_stars'] > context.formData.minStars && r['has_wiki'] === context.formData.hasWiki ); context.adaptableApi.gridApi.loadGridData(tsFrameworks); }, }, ], }, }, ], }, ``` The initial 'JavaScript' DataSet is loaded in the [Adaptable Ready Event](https://www.adaptabletools.com/docs/getting-started-adaptable-ready/index.md) (note a small timeout is used): ```ts setTimeout(() => { adaptableApi.dataSetApi.setDataSet('JavaScript'); }, 200); ``` The DataSetSelected Event Handler is as follows: ```ts adaptableApi.eventApi.on('DataSetSelected', (info: DataSetSelectedInfo) => { if (info.dataSet != null) { switch (info.dataSet.name) { // Note we don't listen to 'TypeScript' as that is handled in the form buttons's onClick case 'HTML': let htmlFrameworks = rowData.filter(r => r['language'] === 'HTML'); adaptableApi.gridApi.loadGridData(htmlFrameworks); break; case 'JavaScript': let jsFrameworks = rowData.filter(r => r['language'] === 'JavaScript'); adaptableApi.gridApi.loadGridData(jsFrameworks); break; } } }); ``` - Switch between the 2 DataSets to see the different data loaded - Use the Form in `TypeScript` to manipulate how many rows are returned to AdapTable ```ts import {AdaptableOptions, DataSetFormContext} from '@adaptabletools/adaptable'; import {rowData} from 'rowData'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Data Set Forms', dataSetOptions: { dataSets: [ { name: 'JavaScript', description: 'JavaScript Frameworks', }, { name: 'TypeScript', description: 'TypeScript Frameworks', form: { fields: [ { name: 'hasWiki', label: 'HasWiki', fieldType: 'checkbox', defaultValue: true, }, { name: 'minStars', label: 'Minimum Stars', defaultValue: 10000, fieldType: 'number', }, { name: 'license', label: 'License', fieldType: 'select', defaultValue: 'MIT License', options: [ { label: 'MIT License', value: 'MIT License', }, { label: 'BSD 3-Clause', value: 'BSD 3-Clause', }, { label: 'Other', value: 'Other', }, ], }, ], buttons: [ { label: 'OK', onClick: (button, context: DataSetFormContext) => { let tsFrameworks = rowData.filter( r => r['language'] === 'TypeScript' && r['license'] == context.formData?.license && r['github_stars'] > context.formData.minStars && r['has_wiki'] === context.formData.hasWiki ); context.adaptableApi.gridApi.loadGridData(tsFrameworks); }, }, ], }, }, ], }, initialState: { Dashboard: { Tabs: [ { Name: 'Data Sets', Toolbars: ['DataSet'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['DataSet'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'license', 'has_wiki', 'created_at', 'updated_at', 'pushed_at', 'github_watchers', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; import {DataSetSelectedInfo} from '@adaptabletools/adaptable'; import {rowData} from 'rowData'; export const onAdaptableReady = (info: AdaptableReadyInfo) => { setTimeout(() => { info.adaptableApi.dataSetApi.setDataSet('JavaScript'); }, 200); info.adaptableApi.eventApi.on( 'DataSetSelected', (info: DataSetSelectedInfo) => { if (info.dataSet?.name === 'JavaScript') { let jsFrameworks = rowData.filter(r => r['language'] === 'JavaScript'); info.adaptableApi.gridApi.loadGridData(jsFrameworks); } } ); }; ``` ```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, enableRowGroup: true, sortable: true, editable: true, filter: true, floatingFilter: true, }, columnDefs: columnDefs, // set row data to null as we will get it later rowData: null, sideBar: true, suppressMenuHide: true, cellSelection: true, statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` --- # Data Set Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-data-set-technical-reference - Data Sets are defined in DataSet Options - Data Set Selected Event is raised when a [Data Set](https://www.adaptabletools.com/docs/handbook-data-sets/index.md) has been selected by the User - Data Set API Section of Adaptable API accesses [Data Set](https://www.adaptabletools.com/docs/handbook-data-sets/index.md) functionality at runtime --- ## DataSet Selected Event The DataSet Selector provides a way to supply an entirely new Data Set to AdapTable based on user selection. This Event is only fired if the DataSet definition **does not** contain a Form If the DataSet contains a Form, any wiring should be done in the `onClick` of the form's submit [Button](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md) ### DataSetSelectedInfo The [`DatasetSelectedInfo`](https://www.adaptabletools.com/docs/reference/datasetselectedinfo.md) object returned by the Event contains the DataSet that has beeen selected: | Property | Type | Description | | --- | --- | --- | | [dataSet](https://www.adaptabletools.com/docs/reference/datasetselectedinfo.md#dataset) | [`DataSet`](https://www.adaptabletools.com/docs/reference/dataset.md) | The DataSet that has been selected | | [adaptableContext](https://www.adaptabletools.com/docs/reference/datasetselectedinfo.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('DataSetSelected', (eventInfo: DataSetSelectedInfo) => { // do something with the info }); ``` --- ## Data Set Options | Property | Type | Description | Default | | --- | --- | --- | --- | | [dataSets](https://www.adaptabletools.com/docs/reference/datasetoptions.md#datasets) | [`DataSet`](https://www.adaptabletools.com/docs/reference/dataset.md)`[]` | Collection of Data Sets to provide data to AdapTable | [] | ### Data Set Object A Data Set is defined as follows: | Property | Type | Description | Default | | --- | --- | --- | --- | | [description](https://www.adaptabletools.com/docs/reference/dataset.md#description) | `string` | Describes the Data Set | | | [form](https://www.adaptabletools.com/docs/reference/dataset.md#form) | [`AdaptableForm`](https://www.adaptabletools.com/docs/reference/adaptableform.md)`<`[`DataSetFormContext`](https://www.adaptabletools.com/docs/reference/datasetformcontext.md)`>` | Params for Data Set popup form | | | [info](https://www.adaptabletools.com/docs/reference/dataset.md#info) | `Record` | Additional info for Data Set | | | [loadData](https://www.adaptabletools.com/docs/reference/dataset.md#loaddata) | `(info: `[`DataSetSelectedInfo`](https://www.adaptabletools.com/docs/reference/datasetselectedinfo.md)`) => TData[] \| Promise` | Optional shortcut that loads row data into the Grid when this Data Set is selected (only when no `form` is defined). Runs before `onSelect`. | undefined | | [name](https://www.adaptabletools.com/docs/reference/dataset.md#name) | `string` | Name of Data Set | | | [onFormSubmit](https://www.adaptabletools.com/docs/reference/dataset.md#onformsubmit) | `(context: `[`DataSetFormContext`](https://www.adaptabletools.com/docs/reference/datasetformcontext.md)`) => void \| Promise` | Invoked when the user submits the Data Set form (Enter key or form button). When no form `buttons` are defined, an OK button is added automatically. | undefined | | [onSelect](https://www.adaptabletools.com/docs/reference/dataset.md#onselect) | `(info: `[`DataSetSelectedInfo`](https://www.adaptabletools.com/docs/reference/datasetselectedinfo.md)`) => void \| Promise` | Invoked when this Data Set is selected and it does not define a `form`. | undefined | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/dataset.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | ### Adaptable Form The form in the Data Set is defined as follows: | Property | Type | Description | Default | | --- | --- | --- | --- | | [buttons](https://www.adaptabletools.com/docs/reference/adaptableform.md#buttons) | [`AdaptableButton`](https://www.adaptabletools.com/docs/reference/adaptablebutton.md)`[]` | Buttons to include in the Form | | | [description](https://www.adaptabletools.com/docs/reference/adaptableform.md#description) | `string` | Additional information to appear in the Form | | | [fields](https://www.adaptabletools.com/docs/reference/adaptableform.md#fields) | `(`[`AdaptableFormField`](https://www.adaptabletools.com/docs/reference/adaptableformfield.md)` \| `[`AdaptableFormField`](https://www.adaptabletools.com/docs/reference/adaptableformfield.md)`[] \| `[`AdaptableFormFieldGroup`](https://www.adaptabletools.com/docs/reference/adaptableformfieldgroup.md)`)[]` | Collection of Dynamic Fields and Field Groups to display. | | | [layout](https://www.adaptabletools.com/docs/reference/adaptableform.md#layout) | [`AdaptableFormLayout`](https://www.adaptabletools.com/docs/reference/adaptableformlayout.md) | How the form's fields are arranged on screen. | 'rows' | | [onSubmit](https://www.adaptabletools.com/docs/reference/adaptableform.md#onsubmit) | `(formData: TData, context: T) => void` | Optional form-level submit hook. | | | [title](https://www.adaptabletools.com/docs/reference/adaptableform.md#title) | `string` | Title to appear in the Form | | --- ## Data Set API | Method | Returns | Description | | --- | --- | --- | | [clearCurrentDataSet()](https://www.adaptabletools.com/docs/reference/datasetapi.md#clearcurrentdataset) | `void` | Clears currently selected Data Set | | [getCurrentDataSet()](https://www.adaptabletools.com/docs/reference/datasetapi.md#getcurrentdataset) | [`DataSet`](https://www.adaptabletools.com/docs/reference/dataset.md)` \| undefined` | Retrieves the currently applied Data Set | | [getDataSetByName(dataSetName)](https://www.adaptabletools.com/docs/reference/datasetapi.md#getdatasetbyname) | [`DataSet`](https://www.adaptabletools.com/docs/reference/dataset.md) | Retrieves Data Set from State with given name | | [getDataSets()](https://www.adaptabletools.com/docs/reference/datasetapi.md#getdatasets) | [`DataSet`](https://www.adaptabletools.com/docs/reference/dataset.md)`[]` | Retrieves the Data Sets from Data Set Options | | [openDataSetSettingsPanel()](https://www.adaptabletools.com/docs/reference/datasetapi.md#opendatasetsettingspanel) | `void` | Opens Settings Panel with Data Set section selected and visible | | [setDataSet(dataSetName)](https://www.adaptabletools.com/docs/reference/datasetapi.md#setdataset) | `void` | Loads the given Data Set (makes it the Current one) | --- # Selecting Data Sets Canonical page: https://www.adaptabletools.com/docs/handbook-data-sets - The DataSet Selector provides a way to supply an entirely new Data Set to AdapTable based on user selection - They are designed for scenarios when there is too much data to send to the client at start-up - Users switch at runtime between the "data sets" provided by Developers at design-time - Data Sets can also include Form Definitions which will be displayed by AdapTable when the DataSet is selected - AdapTable re-populates AG Grid afresh after each selection DataSets are designed to allow developers to supply large amounts of data to AdapTable, while still using AG Grid's [Client Side Row Model](https://www.ag-grid.com/javascript-data-grid/client-side-model/#client-side-row-model). Developers provide a number of different data sets for users to choose from, based on the **same Column set**. - Data Sets cannot be used for providing data which has non-overlapping fields - This is because the same AdapTable instance is being used, and the same AdapTable objects are available - AdapTable objects are usually column-based (e.g. Format Column, Custom Sort) requiring consistent Column sets ## DataSet Selector AdapTable displays all these DataSets in a **DataSet Selector**. - DataSets typically correspond to concepts that make sense to the user's business model - For instance, they can map to a Stored Procedure, or specific time periods, or a regular used category (e.g. 'book') The DataSet Selector appears in the following places in the AdapTable UI: - [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](https://www.adaptabletools.com/docs/ui-status-bar/index.md) ### DataSet Forms DataSets can optionally include Form definitions which allow users to further 'filter' on what data will be returned. Whenever a DataSet with a form definition is selected, AdapTable will dynamically display an [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md). ## Server-Side Row Model Alternative DataSets provide a nice alternative to using the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) as it allows for data to be dynamically retrieved from the server as a response to user selection. However there is no need to build a whole server-side searching and filtering infrastructure - when using datasets, run-time users can filter the returned data set on the client as normal. ## DataSet Selected Event Whenever a DataSet is selected, AdapTable fires the [DataSet Selected Event](https://www.adaptabletools.com/docs/handbook-data-set-technical-reference/index.md). The Event's Info provides details of the newly selected DataSet, allowing developers to supply the associated data as required to AdapTable. - AdapTable performs **no functionality** itself when a DataSet is selected - It simply fires the [DataSet Selected Event](https://www.adaptabletools.com/docs/handbook-data-set-technical-reference/index.md) and event subscribers will provide AdapTable with the relevant data **Example: Using Data Sets** Loading Data in AdapTable with Data Sets - In this slightly contrived example (usually the DataSets are much bigger) we provide 3 DataSets in the `dataSets` property of [Data Set Options](https://www.adaptabletools.com/docs/handbook-data-set-technical-reference/index.md): - `HTML` - loads Frameworks where Language is 'HTML' - `JavaScript` - loads Frameworks where Language is 'JavaScript' - `TypeScript` - loads Frameworks where Language is 'TypeScript' - All 3 subscribe to the [DataSet Selected Event](https://www.adaptabletools.com/docs/handbook-data-set-technical-reference/index.md) and then populate AdapTable using the `loadGridData` function in the [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md) - Switch between the DataSets to see the different data loaded ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Data Sets', dataSetOptions: { dataSets: [ { name: 'HTML', description: 'HTML Frameworks', }, { name: 'JavaScript', description: 'JavaScript Frameworks', }, { name: 'TypeScript', description: 'TypeScript Frameworks', }, ], }, initialState: { Dashboard: { Tabs: [ { Name: 'Data Sets', Toolbars: ['DataSet'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['DataSet'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'license', 'has_wiki', 'created_at', 'updated_at', 'pushed_at', 'github_watchers', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; import {DataSetSelectedInfo} from '@adaptabletools/adaptable'; import {rowData} from 'rowData'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { adaptableApi.eventApi.on('DataSetSelected', (info: DataSetSelectedInfo) => { if (info.dataSet != null) { switch (info.dataSet.name) { case 'HTML': let htmlFrameworks = rowData.filter(r => r['language'] === 'HTML'); adaptableApi.gridApi.loadGridData(htmlFrameworks); break; case 'JavaScript': let jsFrameworks = rowData.filter( r => r['language'] === 'JavaScript' ); adaptableApi.gridApi.loadGridData(jsFrameworks); break; case 'TypeScript': let tsFrameworks = rowData.filter( r => r['language'] === 'TypeScript' ); adaptableApi.gridApi.loadGridData(tsFrameworks); break; } } }); }; ``` ```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, enableRowGroup: true, sortable: true, editable: true, filter: true, floatingFilter: true, }, columnDefs: columnDefs, // set row data to null as we will get it later rowData: null, sideBar: true, suppressMenuHide: true, cellSelection: true, statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` ## Defining Data Sets DataSets are provided in the `dataSets` property of Data Set Options. Each DataSet includes a `name` and `description` together with an optional `form` definition. ### `dataSets` DataSets provided for users to select the Grid's Data Source [`DataSet[]`](https://www.adaptabletools.com/docs/reference/dataset.md) Use this property to set which DataSets are available in AdapTable The [`DataSet`](https://www.adaptabletools.com/docs/reference/datasetf) is defined as follows | Property | Type | Description | Default | | --- | --- | --- | --- | | [description](https://www.adaptabletools.com/docs/reference/dataset.md#description) | `string` | Describes the Data Set | | | [form](https://www.adaptabletools.com/docs/reference/dataset.md#form) | [`AdaptableForm`](https://www.adaptabletools.com/docs/reference/adaptableform.md)`<`[`DataSetFormContext`](https://www.adaptabletools.com/docs/reference/datasetformcontext.md)`>` | Params for Data Set popup form | | | [info](https://www.adaptabletools.com/docs/reference/dataset.md#info) | `Record` | Additional info for Data Set | | | [loadData](https://www.adaptabletools.com/docs/reference/dataset.md#loaddata) | `(info: `[`DataSetSelectedInfo`](https://www.adaptabletools.com/docs/reference/datasetselectedinfo.md)`) => TData[] \| Promise` | Optional shortcut that loads row data into the Grid when this Data Set is selected (only when no `form` is defined). Runs before `onSelect`. | undefined | | [name](https://www.adaptabletools.com/docs/reference/dataset.md#name) | `string` | Name of Data Set | | | [onFormSubmit](https://www.adaptabletools.com/docs/reference/dataset.md#onformsubmit) | `(context: `[`DataSetFormContext`](https://www.adaptabletools.com/docs/reference/datasetformcontext.md)`) => void \| Promise` | Invoked when the user submits the Data Set form (Enter key or form button). When no form `buttons` are defined, an OK button is added automatically. | undefined | | [onSelect](https://www.adaptabletools.com/docs/reference/dataset.md#onselect) | `(info: `[`DataSetSelectedInfo`](https://www.adaptabletools.com/docs/reference/datasetselectedinfo.md)`) => void \| Promise` | Invoked when this Data Set is selected and it does not define a `form`. | undefined | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/dataset.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | ```ts {5} // Create 3 Data Sets - for C#, Java and JavaScript // For JavaScript define a Form which will appear when it is selected const adaptableOptions: AdaptableOptions = { dataSetOptions: { dataSets: [ { name: 'C#', description: 'C# Libraries', }, { name: 'Java', description: 'Java Libraries', }, { name: 'JavaScript', description: 'JavaScript Libraries', form: { fields: [ { name: 'users', label: 'No. of users', defaultValue: 500, fieldType: 'number', }, { name: 'country', label: 'Country', defaultValue: `United States`, fieldType: 'text', }, { name: 'popular', label: 'Popular', fieldType: 'checkbox', defaultValue: true, }, { name: 'framework', label: 'Framework', fieldType: 'select', defaultValue: 'React', options: [ { label: 'React', value: 'react', }, { label: 'Angular', value: 'angular', }, { label: 'Vue', value: 'vue', }, ], }, { name: 'creationDate', label: 'Written', fieldType: 'date', defaultValue: '2010-01-01', }, ], buttons: [ { label: 'OK', onClick: (button, context) => { console.log({button, context}); }, }, ], }, }, ], }, }; ``` ## UI Entitlements [UI Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) behaviour is as follows: - `Full` - DataSets can be selected, and all DataSet UI components are available and display normally - `Hidden` - No DataSet UI components are visible or available - `ReadOnly` - Same as for `Full` --- # Data Entry in AdapTable Canonical page: https://www.adaptabletools.com/docs/handbook-editing - AdapTable provides 4 Modules to ensure fast and safe data entry in AG Grid: - Smart Edit - applies a single mathematical edit to numerous cells - Bulk Update - updates numerous cells with a new value in a single operation - Shortcut - avoid fat finger issues and speed up data entry for numeric columns - Plus Minus - define nudge rules for numeric cells when + or - keys are pressed ## Data Entry Modules AdapTable offers 4 separate Modules / functions to facilitate quick and efficient data entry: | Edit Module | Details | | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | [Smart Edit](https://www.adaptabletools.com/docs/handbook-editing-smart-edit/index.md) | Updates multiple numeric cells with a single operation | | [Bulk Update](https://www.adaptabletools.com/docs/handbook-editing-bulk-update/index.md) | Updates multiple cells to display the same value | | [Shortcuts](https://www.adaptabletools.com/docs/handbook-editing-shortcut/index.md) | Enables quick, safe, numeric data entry via keyboard shortcuts (e.g. M for million) | | [Plus Minus](https://www.adaptabletools.com/docs/handbook-editing-plus-minus/index.md) | Increments / decrements numeric cells when pressing the + / - keys | ## Other Editing Features AdapTable provides many other features to help users edit data quickly and accurately in AG Grid: ### Row Forms [Edit Row Forms](https://www.adaptabletools.com/docs/handbook-row-form/index.md) provide a secure and easy way for users to edit data in AdapTable. AdapTable will display a [dynamic form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) where only the editable fields can be updated. As well as for editing, Row Forms can also be used to create, clone and delete rows ### Cell Editors AdapTable provides 4 [Cell Editors](https://www.adaptabletools.com/docs/handbook-cell-editors/index.md) which help to ensure quick and error-free editing: | Cell Editor | When Used | | ------------------------------------------------------------------------------------- | -------------------------------------------------- | | [Select Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-select/index.md) | Selecting an item from a list of values | | [Numeric Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-numeric/index.md) | Editing numeric columns | | [Date Picker](https://www.adaptabletools.com/docs/handbook-cell-editors-date-picker/index.md) | Editing date columns | | [Percentage Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-percentage/index.md) | Editing numeric values that display as percentages | ### Validating Edits AdapTable provides advanced [Data Validation](https://www.adaptabletools.com/docs/handbook-validating/index.md) capabilities. These can be applied either on the client or your server depending on your requirements. Data Validation can be applied on both user edits and 'ticking' data changes. ### Styling Editable Cells AdapTable allows developers to define and style [Editable and ReadOnly Cells and Columns](https://www.adaptabletools.com/docs/handbook-validating-pre-edit/index.md) in the Grid. - Use `editableCellStyle` and `readOnlyCellStyle` properties in [User Interface Options](https://www.adaptabletools.com/docs/ui-technical-reference/index.md) to style these cells distinctively - There is also an `editedCellStyle` to style Cells which have been edited in the current session ### Data Change History The [Data Change History](https://www.adaptabletools.com/docs/handbook-monitoring-data-change-history/index.md) Module provides full visual coverage of all data edits in AG Grid. These are provided in the _Data Changes Monitor_ which displays details of all cell value changes in the current AdapTable session. An `Undo` Button can be added to each row in the Monitor to allow Users easily to undo data edits they have made --- # Accessing Editing in AdapTable Canonical page: https://www.adaptabletools.com/docs/handbook-editing-accessing - Each of the 4 Editing Modules contains an associated API Class - In addition AdapTable provides a Cell Changed Event which fires when cell contents change ## Cell Changed Event The [Cell Changed Event](https://www.adaptabletools.com/docs/handbook-editing-technical-reference/index.md) fires whenever the contents of any cell changes in AG Grid. This can be the result of a user cell edit or of ticking data. --- # Bulk Update Canonical page: https://www.adaptabletools.com/docs/handbook-editing-bulk-update - Bulk Update replaces, via a single action, the cell value in multiple cells - All the cells will receive the same new value - The new value can either be one that already exists in the column or an entirely new one Bulk Update replaces, via a single action, the cell value in multiple cells in one (editable) Column. All the cells that are updated will display **the same new value**. Bulk Update differs from [Smart Edit](https://www.adaptabletools.com/docs/handbook-editing-smart-edit/index.md) in that it **replaces**, rather than updates, the existing cell value The **replacement** value can either be one that already exists in the column or an entirely new one. ## Using Bulk Update Bulk Update can be applied on **text**, **numeric** and **date** columns. Bulk Updates can be applied in numerous places in the AdapTable UI: - Bulk Update [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md) - available in [Dashboard](https://www.adaptabletools.com/docs/ui-dashboard/index.md) - Bulk Update [Module Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel-module-tool-panels/index.md) - available in [AdapTable Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) - Bulk Update Popup - available via the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) - Bulk Update [Status Bar](https://www.adaptabletools.com/docs/ui-status-bar-technical-reference/index.md) (displays a Button that opens the Bulk Update Popup) ### Applying a Bulk Update There are various Bulk Update UI controls, but they all operate in a very similar fashion: Bulk Update requires that cells are selected from a single editable column. The Column's Data Type can be `numeric`, `string`, or `date`. Right-click in [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) to open the Bulk Update Popup (or click Bulk Update [Status Bar](https://www.adaptabletools.com/docs/ui-status-bar-technical-reference/index.md) button) Alternatively you can access directly apply a Bulk Update from: - the [Bulk Update 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 [Bulk Update Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel-module-tool-panels/index.md) (in the [AdapTable Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md)) The Bulk Update control contains a Dropdown with a distinct list of values for the Column. The values in the dropdown can be provided by developers - see [Providing Custom Column Values when Editing](https://www.adaptabletools.com/docs/handbook-editing-custom-column-values/index.md) for full details You can now either: - Select an existing value from the Dropdown - Type in a new value (and click the "Create" button) Adaptable will perform validation on the proposed Bulk Update. The UI control will tell you if the edit will break validation by displaying an Error icon. A Preview Results table will display (in the Toolbar and Tool Panel - available by clicking the Error Icon) - that will show which of the proposed edits break Validation. If all the Edits are invalid, the *Apply Bulk Update* button is disabled Click the *Apply* button (if validation succeeded) to apply the Bulk Update. **Example: Bulk Update** Updating numerous cells in one operation - This example shows how to apply a Bulk Update. - Select a value in the Bulk Update toolbar and press the Green tick to update the selected cells ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Bulk Update', initialState: { Dashboard: { Tabs: [ { Name: 'Toolbars', Toolbars: ['BulkUpdate'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['BulkUpdate'], }, ], }, 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) => { setTimeout(() => { adaptableApi.gridApi.selectCellRange({ columnIds: ['language'], rowIndexStart: 0, rowIndexEnd: 10, }); }, 10); }; ``` ## Validating Bulk Update AdapTable will check all [Data Validation Rules](https://www.adaptabletools.com/docs/handbook-validating-client/index.md) before appyling a Bulk Update. An info button is shown in the Bulk Update user control indicating the results of the validation check: | Proposed Edits | Info Colour / Type | *Apply Bulk Update* Button Behaviour | | ---------------- | -------------------------- | ------------------------------------------------------ | | All are Valid | Success (default is green) | Button is fully enabled | | Some are Invalid | Warning (default is amber) | Button is enabled but **only** valid edits are applied | | All are Invalid | Error (default is red) | Button is disabled and the operation is not accessible | In addtion AdapTable will display a *Preview Results* table which will indicate - and provide details - of which proposed edits break a Validation Rule. In the Bulk Update [Dashboard Toolbar](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md) and [Module Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel-module-tool-panels/index.md), the table is available by clicking the Error Icon **Example: Bulk Update Validation** Bulk Update validating proposed edits - This example shows what happens when trying to apply a Bulk Update which breaks Validation - We have created a [Data Validation Alert](https://www.adaptabletools.com/docs/handbook-alerting-validation/index.md) that the `Language` column value cannot be "Python" - Trying to enter "Python" in Bulk Update for Language column will not be allowed and the table will display all the failed validations - Enter "Python" in the dropdown in the Bulk Update Toolbar as a *new value* and see the validation results immediately error ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Bulk Update Validation', initialState: { Dashboard: { Tabs: [ { Name: 'Toolbars', Toolbars: ['BulkUpdate'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['BulkUpdate'], }, ], }, Alert: { AlertDefinitions: [ { Name: 'alert-language', Scope: { ColumnIds: ['language'], }, Rule: { Predicates: [ { PredicateId: 'Is', Inputs: ['Python'], }, ], }, AlertProperties: { PreventEdit: true, DisplayNotification: true, }, MessageType: 'Error', MessageText: 'Language cannot be "Python"!', }, ], }, 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) => { setTimeout(() => { adaptableApi.gridApi.selectCellRange({ columnIds: ['language'], rowIndexStart: 0, rowIndexEnd: 10, }); }, 10); }; ``` ## Custom Column Values By default the Bulk Update component 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 instead, via he `customEditColumnValues` property 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 --- # Bulk Update Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-editing-bulk-update-technical-reference - Bulk Update API provides programmatic access to Bulk Update functionality ## Bulk Update API The [`Bulk Update API`](https://www.adaptabletools.com/docs/reference/bulkupdateapi.md) section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) contains functions to apply Bulk Updates programmatically | Method | Returns | Description | | --- | --- | --- | | [getBulkUpdateValue()](https://www.adaptabletools.com/docs/reference/bulkupdateapi.md#getbulkupdatevalue) | `string` | Returns current Bulk Update value | | [openBulkUpdateSettingsPanel()](https://www.adaptabletools.com/docs/reference/bulkupdateapi.md#openbulkupdatesettingspanel) | `void` | Opens Bulk Update Settings Panel | --- # Styling Editable, Read-Only & Edited Cells Canonical page: https://www.adaptabletools.com/docs/handbook-editing-cell-styling - AdapTable allows developers to provide special styles for 3 types of Cells: - Editable - ReadOnly - Previously edited - See the [UI Guide for setting ReadOnly, Editable and Edited Cell Styles](https://www.adaptabletools.com/docs/ui-tutorial-editable-styles/index.md) for more information --- # Providing Custom Column Values when Editing Canonical page: https://www.adaptabletools.com/docs/handbook-editing-custom-column-values - AdapTable usually fetches a Column's distinct values when using the [Select Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-select/index.md) or [Bulk Update dropdown](https://www.adaptabletools.com/docs/handbook-editing-bulk-update/index.md) - Developers are able to override this default behaviour by providing a bespoke list of custom values By default, when using the [Select Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-select/index.md) or the [Bulk Update dropdown](https://www.adaptabletools.com/docs/handbook-editing-bulk-update/index.md), AdapTable will loop through all the values in AG Grid for that column, retrieving and then displaying all 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 a list of bespoke, custom values to be displayed instead. This is provided using the `customEditColumnValues` property in [Edit Options](https://www.adaptabletools.com/docs/handbook-editing-technical-reference/index.md). ### `customEditColumnValues` Provide custom list of values to display in Edit controls [`CustomEditColumnValueInfo[]`](https://www.adaptabletools.com/docs/reference/customeditcolumnvalueinfo.md) Use this property to change the list shown by AdapTable when using Edit controls that display distinct column values. It is a function that receives a [`CustomEditColumnValuesContext`](https://www.adaptabletools.com/docs/reference/customeditcolumnvaluescontext.md) object and returns a [`CustomEditColumnValueInfo`](https://www.adaptabletools.com/docs/reference/customeditcolumnvalueinfo.md) array. The function can also be run asynchronously to return a `Promise` if required The `CustomEditColumnValuesContext` object **received** by the function is defined as follows: | Property | Type | Description | | --- | --- | --- | | [currentSearchValue](https://www.adaptabletools.com/docs/reference/customeditcolumnvaluescontext.md#currentsearchvalue) | `string` | Search text in Edit - used when fetching values from server | | [defaultValues](https://www.adaptabletools.com/docs/reference/customeditcolumnvaluescontext.md#defaultvalues) | `Required<`[`CustomEditColumnValueInfo`](https://www.adaptabletools.com/docs/reference/customeditcolumnvalueinfo.md)`>[]` | Current distinct values in Column | | [gridCell](https://www.adaptabletools.com/docs/reference/customeditcolumnvaluescontext.md#gridcell) | [`GridCell`](https://www.adaptabletools.com/docs/reference/gridcell.md) | Currently edited Grid Cell | | [adaptableContext](https://www.adaptabletools.com/docs/reference/customeditcolumnvaluescontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | The `CustomEditColumnValueInfo` object **returned** by the function (as an array) is defined as follows: | Property | Type | | --- | --- | | [label](https://www.adaptabletools.com/docs/reference/customeditcolumnvalueinfo.md#label) | `string` | | [value](https://www.adaptabletools.com/docs/reference/customeditcolumnvalueinfo.md#value) | `any` | **Example: Edit Custom Values** Providing custom values when editing a Column - In this Demo we provide custom editing values for 2 Columns by using the `customEditColumnValues` property: - `License` - returns 'Permissive', 'LGPL', 'MIT', 'Public Domain' - `Language` - returns a different list for rows where `Licence` is not *MIT License* - Note: we provide a [Select Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-select/index.md) for both columns - Click in a cell in either Column to see the bespoke values - Attempt a Bulk Update on either Column to see the same bespoke values ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Select Editor Data', editOptions: { showSelectCellEditor: context => { return ( context.column.columnId === 'license' || context.column.columnId === 'language' ); }, customEditColumnValues: context => { if (context.column.columnId === 'license') { return [ {label: 'Permissive', value: 'Permissive'}, {label: 'LGPL', value: 'LGPL'}, {label: 'MIT', value: 'MIT'}, {label: 'Public Domain', value: 'Public Domain'}, ]; } if (context.column.columnId === 'language') { return context.gridCell?.rowNode.data['license'] == 'MIT License' ? [ {label: 'JavaScript', value: 'JavaScript'}, {label: 'TypeScript', value: 'TypeScript'}, ] : [ {label: 'HTML', value: 'HTML'}, {label: 'XML', value: 'XML'}, {label: 'CSS', value: 'CSS'}, ]; } return context.defaultValues; }, }, initialState: { Dashboard: {PinnedToolbars: ['BulkUpdate']}, 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', }, ], }, }; ``` --- # Plus Minus Canonical page: https://www.adaptabletools.com/docs/handbook-editing-plus-minus - Plus / Minus increments / decrements numeric cells when the `+` or `-` keys are pressed - Users can set the amount by which the Cell will change - And specify a Nudge Rule which defines whether the Nudge should be applied Plus / Minus updates **editable, numeric cells** quickly and safely in response to a single keyboard input: This is ideal for situations where data needs to be edited incredibly quickly (e.g. if marking to market) - the `+` keyboard key will cause an increment of the cell's value - the `-` keyboard key will cause a decrement of the cell's value It is possible to configure different keyboard keys that will trigger the Nudge (see below) Plus Minus uses **Nudge Rules** - provided by users - which specify: - **where** to apply the Nudge - the **amount** by which to increment or decrement the cell - **when** to apply the Nudge - by providing an optional Rule - Ensure that the `CellSelectionModule` has been provided in [AG Grid Modules](https://www.adaptabletools.com/docs/getting-started-aggrid-modules/index.md) - Additionally make sure that the `cellSelection` property in AG Grid GridOptions is not set to *false* or *null* ## Applying Plus Minus Plus / Minus is applied when the user presses the `+` or `-` keys in numeric cells which are in a Nude Rule Scope. AdapTable will automatically increment or decrement the cell by the Rule's Nudge Value. **Example: Using Plus/Minus** Nudging numeric cells using Plus Minus - This demo has 2 Plus / Minus Rules defined - Nudges in the `GitHub Stars` column change the value by 100 - Nudges in the `GitHub Watchers` column change the value by 200 - Select a cell in the the `GitHub Stars` or `Github Watchers` Columns and press the `+` or `-` key on your Keyboard ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Plus-Minus', initialState: { Theme: {CurrentTheme: 'dark'}, PlusMinus: { PlusMinusNudges: [ // Nudge github_stars by 100 { Name: 'github-stars-nudge-100', Scope: { ColumnIds: ['github_stars'], }, NudgeValue: 100, }, // Nudge github_watchers by 200 { Name: 'github-watchers-nudge-200', Scope: { ColumnIds: ['github_watchers'], }, NudgeValue: 200, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'license', 'github_watchers', 'has_projects', 'has_pages', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'week_issue_change', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, FlashingCell: { FlashingCellDefinitions: [ { Name: 'flashingCell-github', Scope: { ColumnIds: ['github_stars', 'github_watchers'], }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, }, ], }, }, }; ``` ## Plus Minus Rules It is possible to add a Rule to a Plus / Minus Definition. The Rule is a standard [Boolean Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) This sets that the Plus / Minus is only applied by AdapTable if the Rule is evaluated as true. - It is also possible to set 2 (or more) Nudge Definitions one with a Rule, and another without a Rule - The default Nudge Definition will be applied only if all Rules have been evalated and returned *false* **Example: Using Plus/Minus Rules** Applying custom Plus Minus rules - This demo has 3 Plus / Minus Rules defined, all for the `GitHub Stars` column: - Nudge by 500 if the value for the `Language` column in the Row is *TypeScript* - Nudge by 250 if the value for the `Language` column in the Row is *HTML* - Nudge by 10 in all other cases (the default value - when no Rule is applied) - Select a cell in the the `GitHub Stars` column and press the `+` or `-` key on your Keyboard - If `Language` column in the Row is *TypeScript* it will nudge by 500; otherwise it will nude by 10 ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Plus-Minus', initialState: { Theme: {CurrentTheme: 'dark'}, PlusMinus: { PlusMinusNudges: [ // Nudge github_stars by 500 when language is TypeScript { Name: 'github-stars-nudge-500', Scope: { ColumnIds: ['github_stars'], }, Rule: { BooleanExpression: '[language] = "TypeScript"', }, NudgeValue: 500, }, // Nudge github_stars by 250 when language is HTML { Name: 'github-stars-nudge-250', Scope: { ColumnIds: ['github_stars'], }, Rule: { BooleanExpression: '[language] = "HTML"', }, NudgeValue: 250, }, // Nudge github_stars by 10 in all other cases { Name: 'github-stars-nudge-10', Scope: { ColumnIds: ['github_stars'], }, NudgeValue: 10, }, ], }, 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, }, ], }, FlashingCell: { FlashingCellDefinitions: [ { Name: 'flashingCell-github_stars', Scope: { ColumnIds: ['github_stars'], }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, }, ], }, }, }; ``` ## Custom Plus Minus Keys By default Plus Minus Nudges are triggered when the user clicks "+" or "-" keys in the keyboard. However its possible to override these default keys and specify different trigger keys. This can be provided in 2 ways: | Scope | Configuration | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Global** | Using `incrementKey` and `decrementKey` props in `plusMinusOptions` (in [Edit Options](https://www.adaptabletools.com/docs/handbook-editing-technical-reference/index.md)) | | **Per Nudge** | Configuring specific `IncrementKey` and `DecrementKey` values on the Plus Minus object | It is also possible to provide combinations of key strokes e.g `Ctrl + I` or `Shift, Alt + D` The order of evaluation, when checking whether a Nudge Rule has been invoked, is: - first, any specific keys provided in a Nudge Rule - next any bespoke global PlusMinusOptions values provided at design time - finally the default AdapTable Options values specified by AdapTable - This allows you to provide 2 Plus Minus Nudges for all columns (without needing to specify a Rule) - For instance you configure "x" and "y" to increment all numeric columns by 10 and 20 respectively **Example: Custom Plus/Minus Keys** Configuring Custom Plus / Minus Keys - In this example we have changed the defaults keys to increment and decrement in 3 ways: - We globally set default keys of 'u' and 'd' in Plus Minus Options - we see this work if we nudge `Github Watchers` column - We provide bespoke keys of 'f' and 'j' - which we apply to the Nudge Rule in the `Github Stars` column - We provide bespoke keys of 'Ctrl + I' and 'Ctrl + D' - which we apply to the Nudge Rule in the `Issue Change` column - Type 'u' or 'd' in `Github Watchers` column and see the cell value change - Type 'f' or 'j' in `Github Stars` column and see the cell value change - Type 'Ctrl + I' or 'Ctrl + D' in `Issue Change` column and see the cell value change ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Plus-Minus Custom Keys', editOptions: { plusMinusOptions: { incrementKey: 'u', decrementKey: 'd', }, }, initialState: { Theme: {CurrentTheme: 'dark'}, PlusMinus: { PlusMinusNudges: [ // Nudge week_issue_change by 10 using increment keys 'Ctrl + I' and decrement keys 'Ctrl + D' { Name: 'week_issue_change-nudge-10', Scope: { ColumnIds: ['week_issue_change'], }, IncrementKey: 'Ctrl + I', // instead of '+' DecrementKey: 'Ctrl + D', // instead of '-' NudgeValue: 10, }, // Nudge github_stars by 100 using increment key 'f' and decrement key 'j' { Name: 'github-stars-nudge-100', Scope: { ColumnIds: ['github_stars'], }, IncrementKey: 'f', // instead of '+' DecrementKey: 'j', // instead of '-' NudgeValue: 100, }, // Nudge github_watchers by 200 using increment keys defined in PlusMinusOptions { Name: 'github-watchers-nudge-200', Scope: { ColumnIds: ['github_watchers'], }, NudgeValue: 200, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'license', 'github_watchers', 'has_projects', 'week_issue_change', 'has_pages', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, FlashingCell: { FlashingCellDefinitions: [ { Name: 'flashingCell-number', Scope: { DataTypes: ['number'], }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, }, ], }, }, }; ``` ## Keyboard Shortcut Combinations Trigger keys are not limited to single characters: both the global `incrementKey` / `decrementKey` and the per-Nudge `IncrementKey` / `DecrementKey` also accept **keyboard shortcut combinations**. A combination uses `+` as the glue between its parts, for example `shift+Enter` or `ctrl+ArrowDown`. The supported modifiers are: | Modifier | Token | | -------- | ------- | | Control | `ctrl` | | Command | `cmd` | | Alt | `alt` | | Shift | `shift` | - The default single keys (`+` and `-`) continue to work exactly as before - a single character is always treated as a literal key, never as a combination. - Because `+` is the glue between parts, it cannot itself be combined with modifiers (use it as a standalone key instead). **Example: Plus/Minus Key Combinations** Triggering Plus / Minus Nudges with keyboard shortcut combinations - In this example the trigger keys are keyboard shortcut combinations rather than single characters: - We globally set `shift+Enter` / `shift+Backspace` in Plus Minus Options - we see this work if we nudge the `Github Watchers` column - We override these per-Nudge with `ctrl+ArrowUp` / `ctrl+ArrowDown` - which we apply to the `Github Stars` column - Select a cell in the `Github Watchers` column and press `Shift+Enter` or `Shift+Backspace` to change the value - Select a cell in the `Github Stars` column and press `Ctrl+ArrowUp` or `Ctrl+ArrowDown` to change the value ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Plus-Minus Combination Keys', editOptions: { plusMinusOptions: { // Global trigger keys can be keyboard shortcut combinations. // `+` is the glue between parts; supported modifiers are ctrl, cmd, alt and shift. incrementKey: 'shift+Enter', decrementKey: 'shift+Backspace', }, }, initialState: { Theme: {CurrentTheme: 'dark'}, PlusMinus: { PlusMinusNudges: [ // github_stars overrides the global keys with its own combinations { Name: 'github-stars-nudge-100', Scope: { ColumnIds: ['github_stars'], }, IncrementKey: 'ctrl+ArrowUp', // instead of the global 'shift+Enter' DecrementKey: 'ctrl+ArrowDown', // instead of the global 'shift+Backspace' NudgeValue: 100, }, // github_watchers has no keys of its own, so it uses the global combinations { Name: 'github-watchers-nudge-200', Scope: { ColumnIds: ['github_watchers'], }, NudgeValue: 200, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'license', 'github_watchers', 'has_projects', 'has_pages', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'week_issue_change', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, FlashingCell: { FlashingCellDefinitions: [ { Name: 'flashingCell-github', Scope: { ColumnIds: ['github_stars', 'github_watchers'], }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, }, ], }, }, }; ``` ## Creating Plus Minus Nudges Plus / Minus Nudges can be managed at runtime via the Plus / Minus section of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md). This lists the details of all existing Nudge Rules in Adaptable State together with options to: - _create_ (via the Shortcut Wizard) - _edit_ (via the Shortcut Wizard) - _delete_ - _suspend_ - _share_ (if Team Sharing is running) ### Using the Plus / Minus Wizard There are 3 stages to defining a Plus / Minus Nudge Rule: Provide a unique and identifiable name for the Nudge Rule. Either choose which numeric columns which can use the Nudge Rule. Or set the `Number` DataType so that **all** numeric columns can use the Nudge Rule. See [Guide to Column Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) for more on this commonly used object Set the numeric value for the Nudge Rule. This is the amount by which the cell will increment or decrement in response to the key / press. Select this option if the Nudge Rule should be applied whenever the columns in the Scope have the `+` or `-` keys pressed. This is the default value. Write an Expression which needs to be met before the Nudge Value can be applied. This is a Boolean Expression which will be evaluated by AdapTableQL each time the `+` or `-` keys are pressed in scoped cells. Only if the Expression returns `true` will the Nudge Rule value be applied. By default Plus Minus Nudges are triggered when the user clicks "+" or "-" in the keyboard. However its possible to override this on a per-Nudge basis by specifying different keys - either a single key or a keyboard shortcut combination (e.g. `shift+Enter`). ## Defining Plus Minus Nudges Plus / Minus Nudges can be provided at design-time through [Plus Minus Initial Adaptable State](https://www.adaptabletools.com/docs/handbook-editing-plus-minus-technical-reference/index.md) with the following steps: Provide a unique and identifiable name for the Nudge Rule. Specify which numeric columns can use the Nudge Rule. Or set `Number` DataType to include **all** numeric columns. Set the numeric value for the Nudge Rule - the amount by which the cell will increment / decrement in response to key press. Provide an optional Boolean Expression (which will be evaluated by AdapTableQL) specifying when Nudge Value should be applied. Provide custom Keyboard keys to override those provided by AdapTable - either single keys or keyboard shortcut combinations (e.g. `shift+Enter`, `ctrl+ArrowUp`). ```js [[1, 9, "Name"],[1, 14, "Name"],[1, 20, "Name"],[2, 10, "Scope"],[2, 15, "Scope"],[2, 21, "Scope"], [3, 11, "NudgeValue"],[3, 17, "NudgeValue"],[3, 22, "NudgeValue"], [4, 16, "Rule"], [5, 23, "IncrementKey"], [5, 24, "DecrementKey"]] // Set 3 Plus Minus Rules // Bid & Ask columns to nudge by 10 on any key press (using default keyboard keys) // Bid & Ask columns to nudge by 30 when x or y keys are pressed // Bid column - but only when Currency is Euro const initialState: InitialState = { PlusMinus: { PlusMinusNudges: [ { Name: 'bid-ask-10', Scope: { ColumnIds: ['bid', 'ask'] }, NudgeValue: 10, }, { Name: 'bid-eur-20', Scope: { ColumnIds: ['bid'] }, Rule: { BooleanExpression: '[currency]="EUR"'}, NudgeValue: 20, }, { Name: 'bid-ask-30', Scope: { ColumnIds: ['bid', 'ask'] }, NudgeValue: 30, IncrementKey: 'x', DecrementKey: 'y', }, ], }, }; ``` ## UI Entitlements Plus / Minus Nudge Rules with `ReadOnly` Entitlement can be applied but Users cannot manage or suspend them. --- # Plus Minus Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-editing-plus-minus-technical-reference - Plus Minus State contains the Plus Minus Rules - Programmatic access to Plus Minus is through Plus Minus API ## Plus Minus State [`Plus Minus State`](https://www.adaptabletools.com/docs/reference/plusminusstate.md) contains a collection of Plus Minus Rules: | Property | Type | Description | | --- | --- | --- | | [PlusMinusNudges](https://www.adaptabletools.com/docs/reference/plusminusstate.md#plusminusnudges) | [`PlusMinusNudge`](https://www.adaptabletools.com/docs/reference/plusminusnudge.md)`[]` | Array of Plus Minus Nudges | ### Plus Minus A [`Plus Minus Nudge`](https://www.adaptabletools.com/docs/reference/plusminusnudge.md) is defined as follows: | Property | Type | Description | | --- | --- | --- | | [DecrementKey](https://www.adaptabletools.com/docs/reference/plusminusnudge.md#decrementkey) | `string` | Optional keyboard key that decreases cell values for this nudge only (overrides the global `decrementKey` in `plusMinusOptions`). | | [IncrementKey](https://www.adaptabletools.com/docs/reference/plusminusnudge.md#incrementkey) | `string` | Optional keyboard key that increases cell values for this nudge only (overrides the global `incrementKey` in `plusMinusOptions`). | | [Name](https://www.adaptabletools.com/docs/reference/plusminusnudge.md#name) | `string` | Name of the Plus Minus Nudge rule | | [NudgeValue](https://www.adaptabletools.com/docs/reference/plusminusnudge.md#nudgevalue) | `number` | Amount by which to update cell when Rule is applied | | [Rule](https://www.adaptabletools.com/docs/reference/plusminusnudge.md#rule) | [`AdaptableBooleanQuery`](https://www.adaptabletools.com/docs/reference/adaptablebooleanquery.md) | (Optional) Boolean Expression to determine whether to apply the Nudge | | [Scope](https://www.adaptabletools.com/docs/reference/plusminusnudge.md#scope) | [`ColumnScope`](https://www.adaptabletools.com/docs/reference/columnscope.md)`<`[`NumberScopeDataType`](https://www.adaptabletools.com/docs/reference/numberscopedatatype.md)`>` | Numeric columns where the nudge is applied | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/plusminusnudge.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | [IsSuspended](https://www.adaptabletools.com/docs/reference/plusminusnudge.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object | -------------- ## Plus Minus API The [`Plus Minus API`](https://www.adaptabletools.com/docs/reference/plusminusapi.md) section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) enables Plus / Minus Rules to be configured at run-time | Method | Returns | Description | | --- | --- | --- | | [addPlusMinusNudge(plusMinusNudge)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#addplusminusnudge) | [`PlusMinusNudge`](https://www.adaptabletools.com/docs/reference/plusminusnudge.md) | Adds new Plus Minus Rule to State | | [applyPlusMinus(cellUpdateRequests)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#applyplusminus) | `void` | Applies a Plus Minus to given cells | | [deletePlusMinusNudge(plusMinusNudge)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#deleteplusminusnudge) | `void` | Deletes a plus minus rule | | [editPlusMinusNudge(plusMinusNudge)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#editplusminusnudge) | [`PlusMinusNudge`](https://www.adaptabletools.com/docs/reference/plusminusnudge.md) | Replaces Plus Minus Rule in State with given one | | [getAllActivePlusMinus(config)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#getallactiveplusminus) | [`PlusMinusNudge`](https://www.adaptabletools.com/docs/reference/plusminusnudge.md)`[]` | Retrieves all active (not-suspended) Plus Minus Rules in Adaptable State with those with expressions first | | [getAllPlusMinus(config)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#getallplusminus) | [`PlusMinusNudge`](https://www.adaptabletools.com/docs/reference/plusminusnudge.md)`[]` | Retrieves all Plus Minus Rules in Adaptable State with those with expressions first | | [getAllSuspendedPlusMinus(config)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#getallsuspendedplusminus) | [`PlusMinusNudge`](https://www.adaptabletools.com/docs/reference/plusminusnudge.md)`[]` | Retrieves all suspended Plus Minus Rules in Adaptable State with those with expressions first | | [getPlusMinusById(id, config)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#getplusminusbyid) | [`PlusMinusNudge`](https://www.adaptabletools.com/docs/reference/plusminusnudge.md) | Retrieves Plus Minus Rule by the technical ID (from `PlusMinusState`) | | [getPlusMinusNudgeByName(name)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#getplusminusnudgebyname) | [`PlusMinusNudge`](https://www.adaptabletools.com/docs/reference/plusminusnudge.md)` \| undefined` | Retrieves a Plus Minus Nudge by its Name | | [getPlusMinusState()](https://www.adaptabletools.com/docs/reference/plusminusapi.md#getplusminusstate) | [`PlusMinusState`](https://www.adaptabletools.com/docs/reference/plusminusstate.md) | Retrieves Plus Minus section from Adaptable State (nudge rules only). Keyboard triggers are optional on each ; unset fields fall back to `AdaptableOptions.plusMinusOptions`, then `+` / `-`. | | [openPlusMinusSettingsPanel()](https://www.adaptabletools.com/docs/reference/plusminusapi.md#openplusminussettingspanel) | `void` | Opens Settings Panel with Plus Minus section selected and visible | | [runPlusMinusNudge(plusMinusNudge, cells, direction)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#runplusminusnudge) | `void` | Applies a Plus Minus Rule to given cells | | [suspendPlusMinusNudge(plusMinusNudge)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#suspendplusminusnudge) | [`PlusMinusNudge`](https://www.adaptabletools.com/docs/reference/plusminusnudge.md) | Suspends Plus Minus Rule | | [unSuspendPlusMinusNudge(plusMinusNudge)](https://www.adaptabletools.com/docs/reference/plusminusapi.md#unsuspendplusminusnudge) | [`PlusMinusNudge`](https://www.adaptabletools.com/docs/reference/plusminusnudge.md) | Activates a suspended Plus Minus Rule | --- # Shortcuts Canonical page: https://www.adaptabletools.com/docs/handbook-editing-shortcut - Shortcuts ensure that numeric data is edited accurately and quicky into AG Grid - They allow users to avoid "fat finger" issues when editing data quickly - They consist of 4 main elements: - Which Columns can accept the Shortcut - What key will apply the Shortcut - What Operation will be applied when the Key is pressed - What Value will be applied - This allows users to provide a Shortcut where clicking 'M' in a Price column will multiply by 1000 Shortcuts ensure that numeric data is edited accurately and quicky into AG Grid. Each Shortcut consists of an alphabet keystroke which when entered into a numeric cell automatically converts into a mathemetical operation using the existing cell contents. **Example: Using Shortcuts** Editing data quickly using custom Shortcuts - This demo has 2 Shortcuts defined: - All `numeric` columns will multiply by 1,000 when *k* is clicked - The `Github Stars` column will increment by 1 when *p* is clicked ### Expand to see the Shortcut Definitions ```ts initialState: { Shortcut: { Shortcuts: [ { Name: 'Shortcut-K-1', Scope: {DataTypes: ['number']}, ShortcutKey: 'K', ShortcutOperation: 'Multiply', ShortcutValue: 1000, }, { Name: 'Shortcut-P-1', Scope: {ColumnIds: ['github_stars']}, ShortcutKey: 'P', ShortcutOperation: 'Add', ShortcutValue: 1, }, ], }, }, ``` - Double-click any numeric cell to start editing it and then type `k` to multiply by `1.000` - Double-click a cell in the `GitHub Stars` column to start editing it and then type `p` to add `1` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Shortcuts', initialState: { Dashboard: { ModuleButtons: ['Shortcut', 'SettingsPanel'], }, Theme: {CurrentTheme: 'dark'}, Shortcut: { Shortcuts: [ { Name: 'shortcut-K-multiply-1000', Scope: {DataTypes: ['number']}, ShortcutKey: 'K', ShortcutOperation: 'Multiply', ShortcutValue: 1000, }, { Name: 'shortcut-P-add-1', Scope: {ColumnIds: ['github_stars']}, ShortcutKey: 'P', ShortcutOperation: 'Add', ShortcutValue: 1, }, ], }, 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, }, ], }, }, }; ``` ## Applying Shortcuts Shortcuts are applied by pressing the key identified as the `ShortcutKey` in a Shortcut in a numeric cell editor. AdapTable will check if the key press is a valid Shortcut and, if it is, perform the mathematical calculation. For example, a Shortcut of `k` with an operation of `Multiply by 1000` would convert an initial cell value of `5` into `5,000` if the `k` key is pressed on the keyboard. ## Creating Shortcuts Shortcuts can be managed at runtime via the Shortcut section of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md). This lists the details of all existing Shortcuts in Adaptable State together with options to: - *create* (via the Shortcut Wizard) - *edit* (via the Shortcut Wizard) - *delete* - *suspend* - *share* (if Team Sharing is running) ### Using the Shortcut Wizard There are 4 stages to defining a Shortcut: Choose a unique name for the Shortcut. Either choose which numeric columns can use the Shortcut. Or set the `Number` DataType so that **all** numeric columns can use the Shortcut See [Guide to Column Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) for more on this commonly used object Choose which keyboard key will trigger the Shortcut when it is entered into a (correctly scoped) numeric cell. Specify which mathematical operation will be used by AdapTable when the Shortcut is applied. Available values are: `Add`, `Subtract`, `Multiply`, `Divide` Set the numeric value that will be used in conjunction with the current cell value and the mathematical operation to update the cell. Shortcuts with an Entitlement of `ReadOnly` can be applied but Users cannot manage or suspend them. ## Configuring Shortcuts Shortcuts can be provided at design-time through [Shortcut Initial Adaptable State](https://www.adaptabletools.com/docs/handbook-editing-shortcut-technical-reference/index.md). ### Providing a Shortcut in Initial Adaptable State There are 5 stages to defining a Shortcut object: Choose a unique name for the Shortuct ```ts {6,14} const initialState: InitialState = { Shortcut: { Shortcuts: [ { // 'k' multiplies all numeric cells by 1,000 Name: 'Shortcut-M-1', Scope: { DataTypes: ['number'] }, ShortcutKey: 'm', ShortcutValue: 1000, ShortcutOperation: 'Multiply', }, { // 'v' adds 20% VAT to the price, amount columns Name: 'Shortcut-V-1', Scope: { ColumnIds: ['price', 'amount'] }, ShortcutKey: 'v', ShortcutValue: 1.2, ShortcutOperation: 'Multiply', }, ] }, }; ``` Specify which numeric columns can use the Shortcut. Alternatively set a DataType of `Number` so that **all** numeric columns can use the Shortcut See [Guide to Column Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) for more on this commonly used object ```ts {7,15} const initialState: InitialState = { Shortcut: { Shortcuts: [ { // 'k' multiplies all numeric cells by 1,000 Name: 'Shortcut-M-1', Scope: { DataTypes: ['number'] }, ShortcutKey: 'm', ShortcutValue: 1000, ShortcutOperation: 'Multiply', }, { // 'v' adds 20% VAT to the price, amount columns Name: 'Shortcut-V-1', Scope: { ColumnIds: ['price', 'amount'] }, ShortcutKey: 'v', ShortcutValue: 1.2, ShortcutOperation: 'Multiply', }, ] }, }; ``` Choose which keyboard key will trigger the Shortcut when it is entered into a (correctly scoped) numeric cell. The specified value must be a letter of the alphabet. ```ts {8,16} const initialState: InitialState = { Shortcut: { Shortcuts: [ { // 'k' multiplies all numeric cells by 1,000 Name: 'Shortcut-M-1', Scope: { DataTypes: ['number'] }, ShortcutKey: 'm', ShortcutValue: 1000, ShortcutOperation: 'Multiply', }, { // 'v' adds 20% VAT to the price, amount columns Name: 'Shortcut-V-1', Scope: { ColumnIds: ['price', 'amount'] }, ShortcutKey: 'v', ShortcutValue: 1.2, ShortcutOperation: 'Multiply', }, ] }, }; ``` Set the value that will be used in conjunction with the current cell value and the mathematical operation to update the cell. This property must be numeric ```ts {9,17} const initialState: InitialState = { Shortcut: { Shortcuts: [ { // 'k' multiplies all numeric cells by 1,000 Name: 'Shortcut-M-1', Scope: { DataTypes: ['number'] }, ShortcutKey: 'm', ShortcutValue: 1000, ShortcutOperation: 'Multiply', }, { // 'v' adds 20% VAT to the price, amount columns Name: 'Shortcut-V-1', Scope: { ColumnIds: ['price', 'amount'] }, ShortcutKey: 'v', ShortcutValue: 1.2, ShortcutOperation: 'Multiply', }, ] }, }; ``` Specify which mathematical operation will be used by AdapTable when the Shortcut is applied. Available values are: - `Add` - `Subtract` - `Multiply` - `Divide` ```ts {10,18} const initialState: InitialState = { Shortcut: { Shortcuts: [ { // 'k' multiplies all numeric cells by 1,000 Name: 'Shortcut-M-1', Scope: { DataTypes: ['number'] }, ShortcutKey: 'm', ShortcutValue: 1000, ShortcutOperation: 'Multiply', }, { // 'v' adds 20% VAT to the price, amount columns Name: 'Shortcut-V-1', Scope: { ColumnIds: ['price', 'amount'] }, ShortcutKey: 'v', ShortcutValue: 1.2, ShortcutOperation: 'Multiply', }, ] }, }; ``` ## Shortcuts in Row Forms [Row Forms](https://www.adaptabletools.com/docs/handbook-row-form/index.md) are dynamically-created by AdapTable, designed for safe, controlled AG Grid data editing. Any defined Shortcuts will **also** be operative in the numeric input in the Row Form. **Example: Shortcuts in Row Forms** Shortcuts are available also in Row Forms - This demo has a Shortcut defined for `numeric` columns - multiply by 1 Million when **M** is clicked - An `Edit` Action Colummn Command Button has been provided (which opens an Edit [Row](https://www.adaptabletools.com/docs/handbook-row-form/index.md)); the Shortcut is available in this form also - Click the Edit button to open the Edit Form - Type `M` into a numeric cell and not how it multiplies the input's value by 1 Million ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Shortcuts in Row Forms', actionColumnOptions: { actionColumns: [ { columnId: 'action', friendlyName: 'Edit', actionColumnButton: { command: 'edit', }, }, ], }, initialState: { Dashboard: { ModuleButtons: ['Shortcut', 'SettingsPanel'], }, Theme: {CurrentTheme: 'dark'}, Shortcut: { Shortcuts: [ { Name: 'shortcut-M-multiply-1000000', Scope: {DataTypes: ['number']}, ShortcutKey: 'M', ShortcutOperation: 'Multiply', ShortcutValue: 1000000, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'action', '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, }, ], }, }, }; ``` --- # Shortcut Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-editing-shortcut-technical-reference - Shortcuts are defined in Shortcut State - Programmatic access to Shortcuts is through Shortcut API ------------- ## Shortcut State The [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcutstate.md) section of [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) contains a single collection of `Shortcut` objects: | Property | Type | Description | | --- | --- | --- | | [Shortcuts](https://www.adaptabletools.com/docs/reference/shortcutstate.md#shortcuts) | [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcut.md)`[]` | Collection of Shortcuts - designed to speed up data entry | ### Shortcut Object The [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcut.md) object contains 4 mandatory properties: | Property | Type | Description | | --- | --- | --- | | [Name](https://www.adaptabletools.com/docs/reference/shortcut.md#name) | `string` | Name of the Shortcut | | [Scope](https://www.adaptabletools.com/docs/reference/shortcut.md#scope) | [`ColumnScope`](https://www.adaptabletools.com/docs/reference/columnscope.md)`<`[`NumberScopeDataType`](https://www.adaptabletools.com/docs/reference/numberscopedatatype.md)`>` | Numeric Columns where Shortcut is applied | | [ShortcutKey](https://www.adaptabletools.com/docs/reference/shortcut.md#shortcutkey) | `string` | Key which triggers the Shortcut when pressed | | [ShortcutOperation](https://www.adaptabletools.com/docs/reference/shortcut.md#shortcutoperation) | `'Add' \| 'Subtract' \| 'Multiply' \| 'Divide'` | The Operation: 'Add', 'Subtract', 'Multiply', 'Divide' | | [ShortcutValue](https://www.adaptabletools.com/docs/reference/shortcut.md#shortcutvalue) | `number` | Value acting as 2nd operand for ShortcutOperation (1st operand is the cell value) | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/shortcut.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | [IsSuspended](https://www.adaptabletools.com/docs/reference/shortcut.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object | ---------- ## Shortcut API The [`Shortcut API`](https://www.adaptabletools.com/docs/reference/shortcutapi.md) section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) contains many Shortcut-related methods including enabling fetching, creating, editing, deleting and suspending Shortcuts. | Method | Returns | Description | | --- | --- | --- | | [addShortcut(shortcut)](https://www.adaptabletools.com/docs/reference/shortcutapi.md#addshortcut) | [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcut.md) | Adds new Shortcut to the state | | [deleteShortcut(shortcut)](https://www.adaptabletools.com/docs/reference/shortcutapi.md#deleteshortcut) | `void` | Deletes Shortcut from the state | | [editShortcut(shortcut)](https://www.adaptabletools.com/docs/reference/shortcutapi.md#editshortcut) | [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcut.md) | Edits Shortcut in state | | [getActiveShortcuts(config)](https://www.adaptabletools.com/docs/reference/shortcutapi.md#getactiveshortcuts) | [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcut.md)`[]` | Gets all active (not-suspended) Shortcuts in Adaptable State | | [getShortcutById(id, config)](https://www.adaptabletools.com/docs/reference/shortcutapi.md#getshortcutbyid) | [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcut.md) | Retrieves Shortcut by Id | | [getShortcutByName(name)](https://www.adaptabletools.com/docs/reference/shortcutapi.md#getshortcutbyname) | [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcut.md)` \| undefined` | Retrieves a Shortcut by its Name | | [getShortcuts(config)](https://www.adaptabletools.com/docs/reference/shortcutapi.md#getshortcuts) | [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcut.md)`[]` | Gets all Shortcuts in Adaptable State | | [getShortcutState()](https://www.adaptabletools.com/docs/reference/shortcutapi.md#getshortcutstate) | [`ShortcutState`](https://www.adaptabletools.com/docs/reference/shortcutstate.md) | Retrieves Shortcut section from Adaptable State | | [getSuspendedShortcuts(config)](https://www.adaptabletools.com/docs/reference/shortcutapi.md#getsuspendedshortcuts) | [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcut.md)`[]` | Gets all suspended Shortcuts in Adaptable State | | [openShortcutSettingsPanel()](https://www.adaptabletools.com/docs/reference/shortcutapi.md#openshortcutsettingspanel) | `void` | Opens Settings Panel with Shortcut section selected and visible | | [suspendAllShortcut()](https://www.adaptabletools.com/docs/reference/shortcutapi.md#suspendallshortcut) | `void` | Suspends all Shortcuts | | [suspendShortcut(shortcut)](https://www.adaptabletools.com/docs/reference/shortcutapi.md#suspendshortcut) | [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcut.md) | Suspends Shortcut definition | | [unSuspendAllShortcut()](https://www.adaptabletools.com/docs/reference/shortcutapi.md#unsuspendallshortcut) | `void` | Activates all suspended Shortcut | | [unSuspendShortcut(shortcut)](https://www.adaptabletools.com/docs/reference/shortcutapi.md#unsuspendshortcut) | [`Shortcut`](https://www.adaptabletools.com/docs/reference/shortcut.md) | Activates a suspended Shortcut definition | --- # Smart Edit Canonical page: https://www.adaptabletools.com/docs/handbook-editing-smart-edit - Smart Edit applies a single mathematical edit to numerous, numeric cells - The Operation can be either: - one of the 4 System Smart Edit Operations provided by Adaptable - a Custom Smart Edit Operation supplied by a developer at design time Smart Editing enables multiple, contiguous **numeric** cells to be updated with a single mathematical operation. The System Smart Edit Operations - supplied by AdapTable - are: - Addition - Subtraction - Multiplication - Division For example a Smart Edit value of 10 with an operation of Multiply, will multiply all selected cells by 10. ## Applying Smart Edit Smart Edits can be applied in 3 places in AdapTable: - Smart Edit [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md) - Smart Edit [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) - Smart Edit Popup The Smart Edit Popup can also be accessed by selecting `Apply Smart Edit` in the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) ### Applying a Smart Edit All Smart Edit controls operate in a very similar fashion: Smart Edit requires that all selected cells are from a single column, and that could should be numeric and editable. The available Smart Edit Operations are: - Addition - Subtraction - Multiplication - Division Multiplication is selected by AdapTable as the default as it the most commonly applied operation. Additionally developers can provide their own Smart Edit operations via custom functions. Enter a value into the [Numeric Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-numeric/index.md) in the Smart Edit control. This is the value which will be applied to the cell. Adaptable displays a *new values* table showing what the current selected cell values would be if the Smart Edit is applied. This indicates if any of the proposed edits will break validation. In the Tool Bar and Tool Panel this table appears when you click the info button Click the button to apply the Smart Edit. AdapTable re-selects the cells so you can repeat the operation by clicking the button again **Example: Smart Edit** Editing numeric Columns using Smart Edit - This example shows how to use Smart Edit - Click the Green tick in the Smart Edit toolbar to multiply the selected values by 10 ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Smart Edit', initialState: { Dashboard: { Tabs: [ { Name: 'Toolbars', Toolbars: ['SmartEdit'], }, ], }, 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) => { setTimeout(() => { adaptableApi.columnApi.selectColumn('github_stars'); adaptableApi.smartEditApi.setSmartEditValue(10); }, 200); }; ``` ## Custom Smart Edit Operations Developers can provide Custom Smart Edit Operations in addition to those shipped by AdapTable. This is done via the `smartEditCustomOperations` property in the `smartEditOptions` section of [`Edit Options`](https://www.adaptabletools.com/docs/reference/editoptions.md). ### `smartEditCustomOperations` Custom Operations to use in Smart Edit Module [`SmartEditCustomOperation[]`](https://www.adaptabletools.com/docs/reference/smarteditcustomoperation.md) Custom Smart Edit Operations to be provided by Developers in addition to those shipped by AdapTable. Each Custom Operation has 2 properties: - `name` - how the Operation is referenced in the Smart Edit dropdown - `operation` - function invoked by AdapTable when Smart Edit is run, and which returns the new numeric cell value The operation function receives [`SmartEditOperationContext`](https://www.adaptabletools.com/docs/reference/smarteditoperationcontext.md) defined as follows: | Property | Type | Description | | --- | --- | --- | | [currentCell](https://www.adaptabletools.com/docs/reference/smarteditoperationcontext.md#currentcell) | [`GridCell`](https://www.adaptabletools.com/docs/reference/gridcell.md)`` | Current selected grid cell - contains column, row and cell value information | | [smartEditValue](https://www.adaptabletools.com/docs/reference/smarteditoperationcontext.md#smarteditvalue) | `number` | Smart Edit value | | [adaptableContext](https://www.adaptabletools.com/docs/reference/smarteditoperationcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```ts editOptions: { smartEditOptions: { smartEditCustomOperations: [ { name: 'Power', operation: (context: SmartEditOperationContext) => { return Math.pow(context.currentCell.rawValue, context.smartEditValue); }, }, ], }, }, ``` **Example: Smart Edit Custom Operations** Adding bespoke Smart Edit Operations - This example includes 2 Custom Smart Edit Operations: - `Power` - which pows the selected cell by the Smart Edit Value - `bps` - which adds the Smart Edit Value as Basis Points - Note: we have used methods in [Smart Edit API](https://www.adaptabletools.com/docs/handbook-editing-smart-edit-technical-reference/index.md) to set the Smart Edit Operation to `Power` ```ts import { AdaptableOptions, SmartEditOperationContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Smart Edit Custom Operation', editOptions: { smartEditOptions: { customOperations: [ { name: 'Power', operation: (context: SmartEditOperationContext) => { return Math.pow(context.currentCell.rawValue, context.smartEditValue); }, }, { name: 'bps', operation: (context: SmartEditOperationContext) => { const initialValue = context.currentCell.rawValue; const bpChange = context.smartEditValue / 100 / 100; return initialValue + initialValue * bpChange; }, }, ], }, }, initialState: { Dashboard: { Tabs: [ { Name: 'Toolbars', Toolbars: ['SmartEdit'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'week_issue_change', 'github_stars', 'topics', 'license', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'github_watchers', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { setTimeout(() => { adaptableApi.gridApi.selectCellRange({ columnIds: ['week_issue_change'], rowIndexStart: 0, rowIndexEnd: 3, }); adaptableApi.smartEditApi.setCustomSmartEditOperation('Power'); adaptableApi.smartEditApi.setSmartEditValue(2); }, 200); }; ``` ### Smart Edit and Data Validation AdapTable will prevent you from applying a Smart Edit which breaks a [Data Validation Rule](https://www.adaptabletools.com/docs/handbook-validating/index.md) The _new values_ table will indicate - and provide details - if a Smart Edit will break a Validation Rule. In addition AdapTable does the following: | Validation | _Apply Smart Edit_ Button Behaviour | | ---------------- | ---------------------------------------------------------------------------------------- | | All Valid | Has a success colour (default is green) | | Some are Invalid | Has a warning colour (default is amber) and **only** valid edits will be applied | | All are Invalid | Has an error colour (default is red) and is disabled and the operation is not accessible | --- # Smart Edit Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-editing-smart-edit-technical-reference - Smart Edit API provides programmatic access to Smart Editing ## Smart Edit API The [`Smart Edit API`](https://www.adaptabletools.com/docs/reference/smarteditapi.md) section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) contains functions to apply [Smart Edits](https://www.adaptabletools.com/docs/handbook-editing-smart-edit/index.md) programmatically | Method | Returns | Description | | --- | --- | --- | | [getSmartEditCustomOperations()](https://www.adaptabletools.com/docs/reference/smarteditapi.md#getsmarteditcustomoperations) | [`SmartEditCustomOperation`](https://www.adaptabletools.com/docs/reference/smarteditcustomoperation.md)`[]` | Retrieves an Smart Edit Custom Operations (provided in Edit Options) | | [getSmartEditOperation()](https://www.adaptabletools.com/docs/reference/smarteditapi.md#getsmarteditoperation) | [`SmartEditOperation`](https://www.adaptabletools.com/docs/reference/smarteditoperation.md) | Gets current Smart Edit Operation | | [getSmartEditValue()](https://www.adaptabletools.com/docs/reference/smarteditapi.md#getsmarteditvalue) | `number` | Returns current Smart Edit Value | | [openSmartEditSettingsPanel()](https://www.adaptabletools.com/docs/reference/smarteditapi.md#opensmarteditsettingspanel) | `void` | Opens Settings Panel with Smart Edit section selected and visible | | [setCustomSmartEditOperation(customOperationName)](https://www.adaptabletools.com/docs/reference/smarteditapi.md#setcustomsmarteditoperation) | `void` | Sets current Smart Edit Operation to a Custom Operation | | [setSmartEditOperation(operation)](https://www.adaptabletools.com/docs/reference/smarteditapi.md#setsmarteditoperation) | `void` | Sets (shipped) Smart Edit Operation: 'Add','Subtract','Multiply','Divide' | | [setSmartEditValue(smartEditValue)](https://www.adaptabletools.com/docs/reference/smarteditapi.md#setsmarteditvalue) | `void` | Sets Smart Edit Value | --- # Editing Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-editing-technical-reference - Edit Options contains a number of useful editing-related options - Cell Changed Event published by AdapTable whenever the contents of the Cell Changes - Can be the result of a User edit in AG Grid or Ticking data updates - The event provides full details of the change and where in AG Grid it happened -------------- ## Edit Options The [`Edit Options`](https://www.adaptabletools.com/docs/reference/editoptions.md) section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) contains these properties: | Property | Type | Description | Default | | --- | --- | --- | --- | | [customEditColumnValues](https://www.adaptabletools.com/docs/reference/editoptions.md#customeditcolumnvalues) | `(context: `[`CustomEditColumnValuesContext`](https://www.adaptabletools.com/docs/reference/customeditcolumnvaluescontext.md)`) => `[`CustomEditColumnValueInfo`](https://www.adaptabletools.com/docs/reference/customeditcolumnvalueinfo.md)`[] \| Promise<`[`CustomEditColumnValueInfo`](https://www.adaptabletools.com/docs/reference/customeditcolumnvalueinfo.md)`[]>` | List of Column values to display when Editing (i.e. in Edit Lookups, Bulk Update) | | | [displayServerValidationMessages](https://www.adaptabletools.com/docs/reference/editoptions.md#displayservervalidationmessages) | `boolean` | Whether to display message after Server Validation runs | true | | [isCellEditable](https://www.adaptabletools.com/docs/reference/editoptions.md#iscelleditable) | `(cellEditableContext: `[`CellEditableContext`](https://www.adaptabletools.com/docs/reference/celleditablecontext.md)`) => boolean` | Function which checks if a given Grid Cell is editable | | | [plusMinusOptions](https://www.adaptabletools.com/docs/reference/editoptions.md#plusminusoptions) | [`PlusMinusOptions`](https://www.adaptabletools.com/docs/reference/plusminusoptions.md) | Options for Plus Minus module (keyboard increment / decrement) | | | [showSelectCellEditor](https://www.adaptabletools.com/docs/reference/editoptions.md#showselectcelleditor) | `(currentColumContext: `[`AdaptableColumnContext`](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md)`) => boolean` | Columns that will display a Select dropdown when editing | | | [smartEditOptions](https://www.adaptabletools.com/docs/reference/editoptions.md#smarteditoptions) | [`SmartEditOptions`](https://www.adaptabletools.com/docs/reference/smarteditoptions.md)`` | Options for Smart Edit module | | | [validateOnServer](https://www.adaptabletools.com/docs/reference/editoptions.md#validateonserver) | `(serverValidationContext: `[`ServerValidationContext`](https://www.adaptabletools.com/docs/reference/servervalidationcontext.md)`) => Promise<`[`ServerValidationResult`](https://www.adaptabletools.com/docs/reference/servervalidationresult.md)`>` | Function to validate AdapTable data edits remotely | | ### Smart Edit Options The [`Smart Edit Options`](https://www.adaptabletools.com/docs/reference/smarteditoptions.md) section contains these properties: | Property | Type | Description | | --- | --- | --- | | [customOperations](https://www.adaptabletools.com/docs/reference/smarteditoptions.md#customoperations) | [`SmartEditCustomOperation`](https://www.adaptabletools.com/docs/reference/smarteditcustomoperation.md)`[]` | Custom Operations to use in Smart Edit | ### Plus Minus Options The [`Plus Minus Options`](https://www.adaptabletools.com/docs/reference/plusminusoptions.md) section contains these properties: | Property | Type | Description | Default | | --- | --- | --- | --- | | [decrementKey](https://www.adaptabletools.com/docs/reference/plusminusoptions.md#decrementkey) | `string` | Key to decrease cell value for nudges (if not overriden in Plus Minus Rule/Nudge). | '-' | | [incrementKey](https://www.adaptabletools.com/docs/reference/plusminusoptions.md#incrementkey) | `string` | Key to increase cell value for nudges (if not overriden in Plus Minus Rule/Nudge). | '+' | ---------------- ## Cell Changed Event The Cell Changed Event fires whenever the contents of any cell changes in AG Grid. This can be the result of a user cell edit or of ticking data. ### CellChangedInfo The event comprises the [`CellChangedInfo`](https://www.adaptabletools.com/docs/reference/cellchangedinfo.md) object: | Property | Type | Description | | --- | --- | --- | | [cellDataChange](https://www.adaptabletools.com/docs/reference/cellchangedinfo.md#celldatachange) | [`CellDataChangedInfo`](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md) | Object providing full information of the cell (and column and row) that changed | | [adaptableContext](https://www.adaptabletools.com/docs/reference/cellchangedinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | This provides a single `cellChange` property of type [`CellDataChangedInfo`](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md) defined as follows: | 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? | ### 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('CellChanged', (eventInfo: CellChangedInfo) => { // do something with the info }); ``` --- # Exporting Data from AdapTable Canonical page: https://www.adaptabletools.com/docs/handbook-exporting - AdapTable makes it easy to Export data from AG Grid to a destination of the user's choice. - Data is exported from AdapTable in the form of a **Report**. There are 2 types: - System Reports - set of Reports shipped by AdapTable to export all, visible or selected data - Custom Reports - configured by end-users and typically using a Query evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) - Reports are exported using a **Report Format Type**: Excel, VisualExcel, CSV or JSON - Each Report is exported to an **Export Destinations**, of which there are 2 also types: - System Destinations - provided by AdapTable: Downloadable File or Clipboard - Custom Destinations - bespoke destinations provided by developers (e.g. Email, Rest Api etc.) - Developers are also able to configure many elements of export including: - how the export data is formatted - whether to run reports on a schedule Exporting in AdapTable enables data in AG Grid to be sent (in the form of Reports) to other locations. Exporting a Report is a straightforward, 3-step process, comprising 3 elements: 1. A [Report](#reports) - a defined set of rows and columns (provided by AdapTable or created by users) 2. A [Report Format Type](#report-format-types) - one of Excel, VisualExcel, JSON or CSV 3. An [Export Destination](#export-destinations) (either provided by AdapTable or by users) - Export is **not** a WYSIWYG operation - AdapTable exports report **data** and not column styles or row groups etc. - The one exception to this is the `VisualExcel` [Report Format Type](https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type/index.md) which does include [Column Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) Developers can, however, [choose whether exported data](https://www.adaptabletools.com/docs/handbook-exporting-formatting-reports/index.md) contains cell *raw* values (the default) or *display* values **Example: Exporting in AdapTable** Exporting Data from AdapTable - This demo illustrates some of the exporting options in AdapTable (described in greater detail elsewhere in this section). These include: - a [Custom Report](https://www.adaptabletools.com/docs/handbook-exporting-reports-custom/index.md) called `Popular Frameworks` that uses an Expression to export the required data - a [Custom Export Destination](https://www.adaptabletools.com/docs/handbook-exporting-destinations-custom/index.md) of `Rest Endpoint` (though here we just output to the console) - set 2 [Formatting Reports](https://www.adaptabletools.com/docs/handbook-exporting-formatting-reports/index.md) export-formatting related rules (to export formatted cell values and use the format: 'yyyy-dd-MM' for dates) ```ts import {ReportContext} from '@adaptabletools/adaptable'; import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Export Demo', exportOptions: { appendFileTimestamp: true, exportDateFormat: 'yyyy-dd-MM', exportDataFormat: 'formattedValue', customDestinations: [ { name: 'REST Endpoint', onExport: (reportContext: ReportContext) => { console.log('Sending to REST: Report: "' + reportContext.report.Name); console.log('Report data:', reportContext.reportData); }, }, ], }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'Popular Frameworks', CurrentFormat: 'JSON', Reports: [ { Name: 'Popular Frameworks', ReportColumnScope: 'ScopeColumns', ReportRowScope: 'ExpressionRows', Scope: {ColumnIds: ['name', 'language']}, Query: {BooleanExpression: '[github_stars] > 50000 '}, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-created_at', Scope: {ColumnIds: ['created_at']}, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'yyyyMMdd', }, }, }, ], }, 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, }, ], }, }, }; ``` ## Reports There are 2 types of [Reports](https://www.adaptabletools.com/docs/handbook-exporting-reports/index.md) available in AdapTable: - System Reports - shipped by AdapTable and used in most common use cases - Custom Reports - provided by users (in UI or in InitialState) specifying which Columns and Rows to export - Both types of report can be exported using multiple [Report Formats](#report-format-types) to [multiple destinations](#export-destinations) - Custom Reports contain a [Boolean Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) that will be evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) each time the Report is run ## Report Format Types AdapTable enables Reports to be created in 4 different Report Format Types - Excel - Visual Excel (includes styling) - CSV - JSON ## Export Destinations By default exported Reports are available in 2 [System Export Destinations](https://www.adaptabletools.com/docs/handbook-exporting-destinations/index.md) which are shipped by AdapTable: - as a **downloadable File** which the user can download and run as required - sent to the **Clipboard** (for `CSV` and `JSON` Report Format Types only) Depending on whether the appropriate [Plugin](https://www.adaptabletools.com/docs/technical-reference-plugins/index.md) is loaded, Reports can also be exported to [ipushpull](https://www.adaptabletools.com/docs/integrations-ipushpull/index.md) or [OpenFin Excel](https://www.adaptabletools.com/docs/integrations-openfin/index.md) It is also possible to export Reports to [Custom Destinations](https://www.adaptabletools.com/docs/handbook-exporting-destinations-custom/index.md) that are supplied by developers at design-time using the `customDestinations` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md). This enables exporting Grid data to email, PDF, REST Api etc. while still leveraging AdapTable's Export, Expressions, Scheduling and State Management functionality ## Customising Reports AdapTable provides many [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) to configure the behaviour or appearance of Reports. These options include (among others): - configuring which Reports, Report Format Types or Destinations are available to the user in the UI - setting the name of the downloaded file - customizing the exported data e.g. to export formatted data or bespoke formats for Date columns - processing the report - to run it on the server, or to cancel the export - choosing whether to include Column Headers in the exported data - configuring which Columns can be fully excluded from Export See the [Configuring Reports](https://www.adaptabletools.com/docs/handbook-exporting-configuring/index.md), [Formatting Report Data](https://www.adaptabletools.com/docs/handbook-exporting-formatting-reports/index.md) and [Processing Reports](https://www.adaptabletools.com/docs/handbook-exporting-processing/index.md) topics for more information ## Using Export Reports are managed at runtime via the Export section of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md). This lists the details of all Reports, and associated Report Format Types, in Adaptable State with options to: - *Run* with a dropdown showing all available destinations - *Create* (Custom Reports only - via the Export Wizard) - *Edit* (Custom Reports only - via the Export Wizard) - *Delete* - *Suspend* - *[Share](https://www.adaptabletools.com/docs/handbook-team-sharing/index.md)* (if Team Sharing is running) - *[Schedule](https://www.adaptabletools.com/docs/handbook-exporting-scheduling/index.md)* (so they run at a specified time) ### Running Reports Reports can be run from a number of places: - Export [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard/index.md#tabs-and-toolbars) in the Dashboard - Export [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) in the AdapTable ToolPanel Component - Export Status Bar Panel in the [AdapTable Status Bar](https://www.adaptabletools.com/docs/ui-status-bar/index.md) - Export Section in the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md) - Via the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) (`Selected Data` Report only) - Programmatically via methods in the [Export API](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) section of AdapTable API --- # Configuring Export Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-configuring - Developers can configure Export at design time in multiple ways There are many aspects of Export that can be configured by developers, primarily through properties in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md), or functions in [Export API](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md). ## Advanced Exporting By default Export will send the report to the desired destination in a straightforward way. For instance exporting to Excel will create a new workbook with default worksheet settings. However sometimes users want more fine-grained control over the Exported file, e.g. to change the worksheet names, font, or other properties in Excel. This is possible by using the `exportReport` function in [Export API](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md). It takes an optional `exportConfig` property which allows users to modify the params being sent. ### `exportReport` Exports a Report (with fine-grained control if needed) This function allows developers, at run time, to export Reports in AdapTable to any destination. It also provides them with very fine-grained control over the Export. The function definition is: ``` exportReport(name: ReportNameType, format: ReportFormatType, destination?: ExportDestinationType, config?: ExportConfig ): Promise; ``` Basic Exporting You can use this function to export a report to a destination of your choice. ```ts {2} // Export the Current Layout in Visual Export format as a downloadable file adaptableApi.exportApi.exportReport('Current Layout', 'Excel', 'Download') ``` Advanced Exporting The function also allows developers to configure the Export in much more depth. This is due to the `exportConfig` property, which is of type [`ExportConfig`](https://www.adaptabletools.com/docs/reference/exportconfig.md), and defined as follows: | Property | Type | Description | | --- | --- | --- | | [exportParams](https://www.adaptabletools.com/docs/reference/exportconfig.md#exportparams) | `(defaultExportParams: `[`CustomExportParams`](https://www.adaptabletools.com/docs/reference/customexportparams.md)`) => `[`CustomExportParams`](https://www.adaptabletools.com/docs/reference/customexportparams.md) | Function to modify export params; receives default params & returns modified params | | [showProgressIndicator](https://www.adaptabletools.com/docs/reference/exportconfig.md#showprogressindicator) | `boolean` | Whether to show progress indicator | The `exportParams` property is a function which enables overriding of AdapTable's default export behaviour. It receives default params (of type `CustomExportParams`) and returns modified params (also of type `CustomExportParams`): ``` exportParams?: (defaultExportParams: CustomExportParams) => CustomExportParams; ``` The [`CustomExportParams`](https://www.adaptabletools.com/docs/reference/customexportparams.md) object can be one of two AG Grid objects: - `ExcelExportParams` - used for Excel format exports - `CsvExportParams` - used for CSV, JSON and any custom format exports ```ts {2} // Export to Excel but configure the Workbook and Worksheet to meet precise requirements adaptableApi.exportApi.exportReport('Current Layout', 'Excel', 'Download', { exportParams: (exportParams: ExcelExportParams) => { if (!exportParams.processCellCallback) { return exportParams; } const adaptableProcessCellCallback = exportParams.processCellCallback; return { ...exportParams, fileName: 'AdapTable Data', author: 'AdapTable Demos', fontSize: 13, sheetName: context.adaptableApi.layoutApi.getCurrentLayoutName(), headerRowHeight: 50, processCellCallback: params => { // inherits adaptable formatting (Column Format, etc.) const adaptableCellValue = adaptableProcessCellCallback(params); return `Custom ${adaptableCellValue}`; }, }; }, } ); ``` **Example: Configuring Export** Providing fine-grained control over Export in AdapTable - In this demo we export data to Excel and CSV via the `exportReport` function in Export API (using Custom Toolbar Buttons), allowing us add bespoke config: - We export `Current Layout` report to **Excel**, with custom names for Excel Workbook and Worksheet, and changing font and header row height - We export `All Data` report to **CSV**, with custom filename and separator ```ts import { AdaptableButton, AdaptableOptions, CustomExportParams, CustomToolbarButtonContext, GridCellRange, } from '@adaptabletools/adaptable'; import {CsvExportParams, ExcelExportParams} from 'ag-grid-enterprise'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Exporting Reports with Config', dashboardOptions: { customToolbars: [ { name: 'ButtonToolbar', title: 'Buttons', toolbarButtons: [ { label: 'Export to Excel', icon: { name: 'excel', }, buttonStyle: { tone: 'neutral', variant: 'outlined', }, onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { context.adaptableApi.exportApi.exportReport( 'Current Layout', 'Excel', 'Download', { exportParams: (exportParams: CustomExportParams) => { if (!exportParams.processCellCallback) { return exportParams; } const adaptableProcessCellCallback = exportParams.processCellCallback; return { ...exportParams, fileName: 'AdapTable Excel Data', author: 'AdapTable Demos', fontSize: 13, sheetName: context.adaptableApi.layoutApi.getCurrentLayoutName(), headerRowHeight: 50, processCellCallback: params => { // inherits adaptable formatting (Column Format, etc.) const adaptableCellValue = adaptableProcessCellCallback(params); return `Custom ${adaptableCellValue}`; }, }; }, } ); }, }, { label: 'Export to CSV', icon: { name: 'csv', }, buttonStyle: { tone: 'neutral', variant: 'outlined', }, onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { context.adaptableApi.exportApi.exportReport( 'All Data', 'CSV', 'Download', { exportParams: (defaultExportParams: CustomExportParams) => { if (!defaultExportParams.processCellCallback) { return defaultExportParams; } const adaptableProcessCellCallback = defaultExportParams.processCellCallback; return { ...defaultExportParams, fileName: 'AdapTable CSV Data', author: 'AdapTable Demos', columnSeparator: '|', processCellCallback: params => { // inherits adaptable formatting (Column Format, etc.) const adaptableCellValue = adaptableProcessCellCallback(params); return `Custom ${adaptableCellValue}`; }, }; }, } ); }, }, ], }, ], }, initialState: { Dashboard: {PinnedToolbars: ['ButtonToolbar']}, 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, }, ], }, }, }; ``` ## Configuring Report File Names By default the name of the file created in an Export is that of the exported Report Name (e.g. 'All Data'). There are 2 options available in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) to change this behaviour: - `appendFileTimestamp` which appends a Timestamp to the Report name ### `appendFileTimestamp` Whether to add a timestamp as a suffix to exported file name The timestamp always takes the form 'yyyyMMdd_HHmmss'. For example exporting the 'All Data' report on 1 Jan at 10:15 am will produce: 'All_Data_20250101_101500.xls' ```ts {4} // Add a Timestamp to the name of the exported report const adaptableOptions: AdaptableOptions = { exportOptions: { appendFileTimestamp: true, } } ``` - `reportFilename` which allows a completely different Report name to be used ### `reportFilename` Function enabling bespoke Report file names Use this property to override AdapTable's default Report file name with a besoke implementation. The function receives a [`ReportFileNameContext`](https://www.adaptabletools.com/docs/reference/reportfilenamecontext.md) object and returns a boolean: ```ts reportFilename?(reportFileNameContext: ReportFileNameContext): string; ``` The `ReportFileNameContext` object contains just 1 property: | Property | Type | Description | | --- | --- | --- | | [fileName](https://www.adaptabletools.com/docs/reference/reportfilenamecontext.md#filename) | `string` | Default File Name to use | | [adaptableContext](https://www.adaptabletools.com/docs/reference/reportfilenamecontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | but also extends [`BaseExportContext`](https://www.adaptabletools.com/docs/reference/baseexportcontext.md) | Property | Type | Description | | --- | --- | --- | | [exportDestination](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#exportdestination) | [`ExportDestinationType`](https://www.adaptabletools.com/docs/reference/exportdestinationtype.md) | Export Destination for the Report | | [report](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#report) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md) | The Report Configuration being run | | [reportFormat](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#reportformat) | [`ReportFormatType`](https://www.adaptabletools.com/docs/reference/reportformattype.md) | Format of the Report being run | | [reportName](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#reportname) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md) | Name of the Report being run | | [adaptableContext](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```ts {4,5,6,7,8,9} // Change the File Name for "All Data" Report const adaptableOptions: AdaptableOptions = { exportOptions: { reportFilename: (reportFileNameContext: ReportFileNameContext) => { return reportFileNameContext.reportName == 'All Data' ? `Current Grid Data Sent to ${ reportFileNameContext.destination } on ${new Date().toDateString()}` : reportFileNameContext.fileName; }, } } ``` **Example: Configuring Report FileNames** Configuring the Names of the Report Files in Export - In this example we provide a custom File Name - but just for the "All Data" Report ```ts import { AdaptableOptions, ReportFileNameContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Configuring Report FileName', exportOptions: { reportFilename: (reportFileNameContext: ReportFileNameContext) => { return ( reportFileNameContext.reportName + ' Sent to ' + reportFileNameContext.exportDestination + ' with format ' + reportFileNameContext.reportFormat ); }, }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'All Data', CurrentFormat: 'JSON', }, 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, }, ], }, }, }; ``` ## Setting Exportable Columns By default **every** Column in AdapTable is exportable. This means that it can be included in System Reports (e.g. `All Data`) and will be available in UI for selection. This can be set to false for any Column via the `isColumnExportable` property in Export Options. ### `isColumnExportable` Whether a Column is exportable This property is in the form of a function which takes an [`AdaptableColumnContext`](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md) object and returns a Boolean. ```ts isColumnExportable?: (context: AdaptableColumnContext) => boolean; ``` The `AdaptableColumnContext` simply includes details of the given column to check. ```ts {4} // Only allow 4 Columns to be included in Reports const adaptableOptions: AdaptableOptions = { exportOptions: { isColumnExportable: (context: AdaptableColumnContext) => ['name', 'github_stars', 'language', 'github_watchers',].includes( context.column.columnId ), } } ``` **Example: Setting Exportable Columns** Configuring which columns are exportable - In this example we dont export the `Language` Column, nor any `Date` Columns ```ts import { AdaptableColumnContext, AdaptableOptions, BaseExportContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Configuring Exportable Columns', exportOptions: { isColumnExportable: (context: AdaptableColumnContext) => context.column.columnId !== 'language' && context.column.dataType !== 'date', }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'All Data', CurrentFormat: 'Excel', }, 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, }, ], }, }, }; ``` ## Skipping Column Headers By default AdapTable will include the Column Headers in the Export. This can be set to false all or some Reports via the `skipColumnHeaders` property in Export Options. ### `skipColumnHeaders` Whether to include Column Headers in Report This property is in the form of a boolean or a function which takes an [`BaseExportContext`](https://www.adaptabletools.com/docs/reference/baseexportcontext.md) object and returns a Boolean. ```ts skipColumnHeaders?: boolean | ((skipColumnHeadersContext: BaseExportContext) => boolean); ``` The `BaseExportContext` provides details of the report being exported: | Property | Type | Description | | --- | --- | --- | | [exportDestination](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#exportdestination) | [`ExportDestinationType`](https://www.adaptabletools.com/docs/reference/exportdestinationtype.md) | Export Destination for the Report | | [report](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#report) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md) | The Report Configuration being run | | [reportFormat](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#reportformat) | [`ReportFormatType`](https://www.adaptabletools.com/docs/reference/reportformattype.md) | Format of the Report being run | | [reportName](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#reportname) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md) | Name of the Report being run | | [adaptableContext](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```ts {4} // Don't include Column Header in the All Data Report const adaptableOptions: AdaptableOptions = { exportOptions: { skipColumnHeaders: (context: BaseExportContext) => { return context.reportName === 'All Data'; }, } } ``` **Example: Skipping Column Headers** Excluding Column Headers from exported Report - In this example we exclude Custom Headers from the "All Data" Report only ```ts import {AdaptableOptions, BaseExportContext} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Configuring Report Column Headers', exportOptions: { skipColumnHeaders: (context: BaseExportContext) => { return context.reportName === 'All Data'; }, }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'All Data', CurrentFormat: 'Excel', }, 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, }, ], }, }, }; ``` --- # Report Destinations Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-destinations - AdapTable provides 2 System Export Destinations for Reports: `Download` and `Clipboard` - Developers can configure which are available - including on a per Report basis The Report Export Destination determines where a Report is sent. ## System Export Destinations AdapTable ships with 2 Export Destinations - `Download` - available for **all** Report Formats - `Clipboard` - available only for `CSV` and `JSON` Report Formats - The Export button displays a dropdown showing all available Destinations for current Report and Report Format - However, if the Report can only have a single Destination, the Export button becomes a regular button ### Limiting System Destinations By default both System Export Destinations are available to users. Where this is not required behaviour, use the `systemExportDestinations` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md). The property returns a list (either directly or via a function) of which System Destinations should be available. ### `systemExportDestinations` Sets which Export Destinations provided by AdapTable are available for Reports [`SystemExportDestinations[]`](https://www.adaptabletools.com/docs/reference/systemexportdestination.md) Use this property to specify a custom list of the System Destinations which should be available to users. You can return either an array of destinations, or provide a function which returns an array. Hard Coded List The simplest method is to return an array listing which System Destinations should be available: ```ts {4} // Make only the 'Download' System Export Destination available (hiding the Clipboard) const adaptableOptions: AdaptableOptions = { exportOptions: { systemExportDestinations: ['Download'], } } ``` Provide an **empty** array if you want **none** to be available: ```ts {4} // Show No System Export Destinations const adaptableOptions: AdaptableOptions = { exportOptions: { systemExportDestinations: [], } } ``` Via a Function Alternatively, you can provide a function which returns the System Destinations. The function receives context of type [`SystemExportDestinationsContext`](https://www.adaptabletools.com/docs/reference/systemexportdestinationscontext.md) defined as follows: | Property | Type | Description | | --- | --- | --- | | [currentLayoutName](https://www.adaptabletools.com/docs/reference/systemexportdestinationscontext.md#currentlayoutname) | `string` | Name of current Layout | | [currentReportFormat](https://www.adaptabletools.com/docs/reference/systemexportdestinationscontext.md#currentreportformat) | [`ReportFormatType`](https://www.adaptabletools.com/docs/reference/reportformattype.md) | Format of current Report | | [currentReportName](https://www.adaptabletools.com/docs/reference/systemexportdestinationscontext.md#currentreportname) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md) | Name of current Report | | [defaultSystemExportDestinations](https://www.adaptabletools.com/docs/reference/systemexportdestinationscontext.md#defaultsystemexportdestinations) | [`SystemExportDestination`](https://www.adaptabletools.com/docs/reference/systemexportdestination.md)`[]` | Default System Export Destinations | | [adaptableContext](https://www.adaptabletools.com/docs/reference/systemexportdestinationscontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```ts {4} // Only Export to Download for the 'All Data' report const adaptableOptions: AdaptableOptions = { exportOptions: { systemExportDestinations: (context: SystemExportDestinationsContext) => { return context.currentReportName == 'All Data' ? ['Download'] : context.defaultSystemExportDestinations; }, } } ``` **Example: Configuring System Export Destinations** Configuring which System Export Destinations are available - In this example AdapTable has been limited to just the Clipboard System Export Destination ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Configuring System Export Destinations', exportOptions: { systemExportDestinations: ['Clipboard'], }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'All Data', CurrentFormat: 'CSV', }, 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 Export Destinations If the System Export Destinations provided by AdapTable are insufficient, developers can easily supply their own custom export destinations. See the [Guide to creating Custom Export Destinations](https://www.adaptabletools.com/docs/handbook-exporting-destinations-custom/index.md) for more information --- # Custom Export Destinations Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-destinations-custom - AdapTable System Export Destinations can be supplemented by Custom Destinations provided by developers - Custom Destinations can be provided by Developers in 2 ways: - an `onExport` function that is automatically invoked by AdapTable - an [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) when bespoke information is required by the runtime user prior to export If the [System Export Destinations](https://www.adaptabletools.com/docs/handbook-exporting-destinations/index.md) provided by AdapTable are insufficient, developers can easily supply their own custom export destinations. This is done via the `customDestinations` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md). The property returns a list (either directly or via a function) of which Custom Destinations are available. ### `customDestinations` User-provided Report Destinations (used in addition to those shipped in AdapTable) [`CustomDestination[]`](https://www.adaptabletools.com/docs/reference/customdestination.md) These are Export Destinations provided by developers at design-time. The [`CustomDestination`](https://www.adaptabletools.com/docs/reference/customdestination.md) object is defined as follows: | Property | Type | Description | | --- | --- | --- | | [form](https://www.adaptabletools.com/docs/reference/customdestination.md#form) | [`AdaptableForm`](https://www.adaptabletools.com/docs/reference/adaptableform.md)`<`[`ExportFormContext`](https://www.adaptabletools.com/docs/reference/exportformcontext.md)`>` | Optional Adaptable Form; if provided, it must include Buttons that will execute the Export | | [name](https://www.adaptabletools.com/docs/reference/customdestination.md#name) | `string` | Name of Custom Destination (mandatory) | | [onExport](https://www.adaptabletools.com/docs/reference/customdestination.md#onexport) | `(reportContext: `[`ReportContext`](https://www.adaptabletools.com/docs/reference/reportcontext.md)`) => void` | Optional Function invoked when Export is applied (used if no form is supplied) | You can provide either an array of custom destinations, or provide a function which returns an array. Hard Coded List The simplest method is to return an array of the Custom Destinations you wish to be available: ```ts {3} const adaptableOptions: AdaptableOptions = { exportOptions: { customDestinations: [ { name: 'Destination 1', // in practice more props will be provided }, { name: 'Destination 2', // in practice more props will be provided }, ], }, }; ``` Via a Function Alternatively, you can provide a function which returns the Custom Destinations. The function receives context of type [`CustomDestinationsContext`](https://www.adaptabletools.com/docs/reference/customdestinationscontext.md) defined as follows: | Property | Type | Description | | --- | --- | --- | | [currentLayoutName](https://www.adaptabletools.com/docs/reference/customdestinationscontext.md#currentlayoutname) | `string` | Name of current Layout | | [currentReportFormat](https://www.adaptabletools.com/docs/reference/customdestinationscontext.md#currentreportformat) | [`ReportFormatType`](https://www.adaptabletools.com/docs/reference/reportformattype.md) | Format of current Report | | [currentReportName](https://www.adaptabletools.com/docs/reference/customdestinationscontext.md#currentreportname) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md) | Name of current Report | | [adaptableContext](https://www.adaptabletools.com/docs/reference/customdestinationscontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```ts {4} // Return just 1 Custom Destination for Current Layout Report const adaptableOptions: AdaptableOptions = { exportOptions: { exportOptions: { customDestinations: (context: CustomDestinationsContext) => { return context.currentReportName == 'Current Layout' ? [ { name: 'Destination 1', // in practice more props will be provided }, ] : [ { name: 'Destination 1', // in practice more props will be provided }, { name: 'Destination 2', // in practice more props will be provided }, ]; }, }, }, }; ``` - This allows you to export grid data to email, PDF, REST Apis and other locations you require - And you can still leverage AdapTable's Reports, Expressions, Scheduling and State Management functionality ## Defining a Custom Destination The Custom Destination object is defined as follows: | Property | Type | Description | | --- | --- | --- | | [form](https://www.adaptabletools.com/docs/reference/customdestination.md#form) | [`AdaptableForm`](https://www.adaptabletools.com/docs/reference/adaptableform.md)`<`[`ExportFormContext`](https://www.adaptabletools.com/docs/reference/exportformcontext.md)`>` | Optional Adaptable Form; if provided, it must include Buttons that will execute the Export | | [name](https://www.adaptabletools.com/docs/reference/customdestination.md#name) | `string` | Name of Custom Destination (mandatory) | | [onExport](https://www.adaptabletools.com/docs/reference/customdestination.md#onexport) | `(reportContext: `[`ReportContext`](https://www.adaptabletools.com/docs/reference/reportcontext.md)`) => void` | Optional Function invoked when Export is applied (used if no form is supplied) | As can be seen, it has a mandatory `name` property, and depending on the complexity required, there are 2 (mutually exclusive) ways of providing the Custom Destination implementation: - an `onExport` function that is invoked by AdapTable automatically - an [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) if bespoke information is required by the runtime user prior to export ### Using an `onExport` function In this use case, the developer needs to provide an implementation for the `onExport` function. This function will then be invoked by AdapTable whenever a report is exported to the Custom Destination. ### Using the onExport function The `onExport` function receives a `reportContext` object (containing all the report data required) and returns void: ```tsx onExport: (reportContext: ReportContext) => void; ``` The [`ReportContext`](https://www.adaptabletools.com/docs/reference/reportcontext.md) object is defined as follows: | Property | Type | Description | | --- | --- | --- | | [reportData](https://www.adaptabletools.com/docs/reference/reportcontext.md#reportdata) | [`ExportResultData`](https://www.adaptabletools.com/docs/reference/exportresultdata.md) | Export Data for the Report | | [adaptableContext](https://www.adaptabletools.com/docs/reference/reportcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | The `reportData` property is of type [`ReportData`](https://www.adaptabletools.com/docs/reference/reportdata.md) which contains all the data being exported: | Property | Type | Description | | --- | --- | --- | | [columns](https://www.adaptabletools.com/docs/reference/reportdata.md#columns) | [`ReportColumn`](https://www.adaptabletools.com/docs/reference/reportcolumn.md)`[]` | Columns in the Report | | [groupColumnIds](https://www.adaptabletools.com/docs/reference/reportdata.md#groupcolumnids) | `string[]` | Group columns IDs in the Report | | [pivotColumnIds](https://www.adaptabletools.com/docs/reference/reportdata.md#pivotcolumnids) | `string[]` | Pivot columns IDs in the Report | | [rows](https://www.adaptabletools.com/docs/reference/reportdata.md#rows) | `Record[]` | Row Data in the Report | The `ReportContext` object itself derives from [`BaseExportContext`](https://www.adaptabletools.com/docs/reference/baseexportcontext.md) which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [exportDestination](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#exportdestination) | [`ExportDestinationType`](https://www.adaptabletools.com/docs/reference/exportdestinationtype.md) | Export Destination for the Report | | [report](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#report) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md) | The Report Configuration being run | | [reportFormat](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#reportformat) | [`ReportFormatType`](https://www.adaptabletools.com/docs/reference/reportformattype.md) | Format of the Report being run | | [reportName](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#reportname) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md) | Name of the Report being run | | [adaptableContext](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | **Example: Custom Export Destination via Function** Custom Export Destination: via a Function - This example contains a Custom Export Destination - `Rest Endpoint` - It provides an implementation for the `onExport` function, that is invoked when the Report runs - Note: the demo simply sends a [System Status](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md) message with the Report's name (and console logs its data), but a "real world" application's implementation would send the data to a REST endpoint ```ts import {ExportResultData} from '@adaptabletools/adaptable/src/AdaptableOptions/ExportOptions'; import {AdaptableOptions, ReportContext} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom Export Destination: Function', exportOptions: { customDestinations: [ { name: 'REST Endpoint', onExport: (reportContext: ReportContext) => { const reportData: ExportResultData = reportContext.reportData; const header: string = 'Sending to REST - Report: "' + reportContext.report.Name; reportContext.adaptableApi.systemStatusApi.setInfoSystemStatus( header ); console.log('Report data:', reportData); }, }, ], }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export', 'SystemStatus'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export', 'SystemStatus'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'All Data', }, 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, }, ], }, }, }; ``` ### Defining an AdapTable Form It might sometimes be necessary for users to provide **additional** information regarding the custom destination e.g. an email address. This is done by including an [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) definition in the Custom Destination. AdapTable will read this form definition metadata and display the form dynamically (including default values). See [Guide to defining an Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) for full details The form can include as many field definitions as required, together with optional default values if needed. For the form to be effective it must include a **Submit Button** with an `onClick` property that performs the Export. - When providing a form AdapTable will **not** perform the Export automatically - It is your responsibility to provide a button with an `onClick` function which will export the data ### Providing an AdapTable Form The submit Button is an [Adaptable Button](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md) which has the usual disabled, hidden and onClick functions. The Button can also be used to perform validation e.g. remain disabled until the form fields are all valid. All the button's properties will receive as a parameter the [`ExportFormContext`](https://www.adaptabletools.com/docs/reference/exportformcontext.md) object which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [customDestination](https://www.adaptabletools.com/docs/reference/exportformcontext.md#customdestination) | [`CustomDestination`](https://www.adaptabletools.com/docs/reference/customdestination.md) | Custom Export destination | | [report](https://www.adaptabletools.com/docs/reference/exportformcontext.md#report) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md) | The exported report | | [reportData](https://www.adaptabletools.com/docs/reference/exportformcontext.md#reportdata) | [`ExportResultData`](https://www.adaptabletools.com/docs/reference/exportresultdata.md) | The data in the report | | [adaptableContext](https://www.adaptabletools.com/docs/reference/exportformcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | The [`ReportData`](https://www.adaptabletools.com/docs/reference/reportdata.md) object comprises multiple properties which contain all the data being exported: | Property | Type | Description | | --- | --- | --- | | [columns](https://www.adaptabletools.com/docs/reference/reportdata.md#columns) | [`ReportColumn`](https://www.adaptabletools.com/docs/reference/reportcolumn.md)`[]` | Columns in the Report | | [groupColumnIds](https://www.adaptabletools.com/docs/reference/reportdata.md#groupcolumnids) | `string[]` | Group columns IDs in the Report | | [pivotColumnIds](https://www.adaptabletools.com/docs/reference/reportdata.md#pivotcolumnids) | `string[]` | Pivot columns IDs in the Report | | [rows](https://www.adaptabletools.com/docs/reference/reportdata.md#rows) | `Record[]` | Row Data in the Report | See the [Adaptable Button Tutorial](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md) for further information on configuring Buttons - Custom Destination can also be included in a [Scheduled Export](https://www.adaptabletools.com/docs/handbook-exporting-scheduling/index.md) - The same dynamic form and its associated form fields and buttons will be displayed in the Schedule Wizard **Example: Custom Export Destination via a Form** Custom Export Destination: via a Form - This example contains a Custom Export Destination - `Email` which uses an [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) that displays automatically when the Export is invoked - The Form contains a number of input fields: - Dropdown with pre-selected _Email Addresses_ - Textboxes for _Subject_ (pre-populated) and _Body_ - Checkbox for _Including Headers_ - The Form also contains validation - the `Export` button cannot be clicked if the Email Body input is blank - The `onClick` property of the `Export` Button simply sends the data as a [System Status](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md) (but a real world example will be different) - We also removed all System Export Destinations so that **only** the Custom Destination is available ```ts import { AdaptableButton, AdaptableOptions, ExportFormContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom Export Destination: Form', exportOptions: { customDestinations: [ { name: 'Email', form: { title: 'Email Settings', description: 'Provide email details', fields: [ { name: 'emailAddress', label: 'Email Address', fieldType: 'select', options: [ { value: 'support@adaptabletools.com', label: 'Support', }, { value: 'sales@adaptabletools.com', label: 'Sales', }, ], defaultValue: 'support@adaptabletools.com', }, { name: 'emailSubject', label: 'Email Subject', fieldType: 'text', defaultValue: 'AdapTable Report Data', }, { name: 'emailBody', label: 'Email Body', fieldType: 'text', }, { name: 'includeHeaders', label: 'Include Headers', fieldType: 'checkbox', }, ], buttons: [ { label: 'Cancel', }, { label: 'Export', buttonStyle: { tone: 'success', variant: 'raised', }, disabled: ( button: AdaptableButton, context: ExportFormContext ) => { const subject: any = context.formData?.['emailSubject']; const body: any = context.formData?.['emailBody']; return subject == '' || body == ''; }, onClick: ( button: AdaptableButton, context: ExportFormContext ) => { // send the report to an email address // the context contains the report data const message = `Sending to Email: Report: "${context.report.Name}" with format: ${context.reportData.type} to ${context.formData?.['emailAddress']}`; const info = `Report contains: Columns: ${context.report.ReportColumnScope}, Rows: ${context.report.ReportRowScope}`; context.adaptableApi.systemStatusApi.setSuccessSystemStatus( message, info ); }, }, ], }, }, ], systemExportDestinations: [], }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export', 'SystemStatus'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export', 'SystemStatus'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'All Data', CurrentFormat: 'Excel', }, 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, }, ], }, }, }; ``` --- # Formatting Report Data Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-formatting-reports - AdapTable provides a range of options to allow developers to configure how report data is formatted - These include choosing whether to export the "display" (rather than "raw") value of the cell - Additionally Dates can be given a bespoke format AdapTable allows developers to configure how the data in exported Reports is formatted. These is done via 2 (similar-sounding) properties in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md): - `exportDataFormat` - use the [Display Value](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) (instead of the Raw Value) - for all, or a subset of, Columns - `exportDateFormat` - provides a bespoke export format for [Date columns](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) See [Processing Reports](https://www.adaptabletools.com/docs/handbook-exporting-processing/index.md) for an even more fine-grained approach, where the exported values can also be changed ## Display Values By default AdapTable exports the underlying **raw data** in AG Grid. - A value of 12.59 which has been formatted as "£12.59 (GBP)" will have the raw value sent to Excel - This means that it can be identified as a number and treated accordingly This is by **design**: AdapTable provides a data export function not a WYSIWYG operation. The sole exception is when using the `VisualExcel` [Report Format Type](https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type/index.md) which always and only exports Display Values If this behaviour is not wanted, it can be changed using the `exportDataFormat` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md). This property allows you configuring exporting using the Display Value for: - **All Columns** in all exports - by **Column Data Type** (i.e. different rules for string, number and date Columns) - on a **per-Column** basis (by using a function) ### `exportDataFormat` Format of exported data By default AdapTable exports the underlying **raw data** in AG Grid. This property is ignored when using the `VisualExcel` [Report Format Type](https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type/index.md) as it only exports Display Format Set the `exportDataFormat` property to `formattedValue` to export the *Display Value* of the column instead. - The display value could be supplied by an AG Grid ValueFormatter or ValueGetter - Alternatively - and preferably - it can use AdapTable's [Column Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) As can be seen from the property definition, it provides 3 possible return types: ```ts exportDataFormat?: | DataFormatType | DataFormatDataType | ((context: AdaptableColumnContext) => DataFormatType); ``` 1. DataFormatType The most straightforward is to return a [`DataFormatType`](https://www.adaptabletools.com/docs/reference/dataformattype.md) object which will be applied to **every column** being exported. This object returns either `rawValue` (the default) or `formattedValue` (which returns the display value). ```ts {4} // Set the Format Type to be `formattedValue' in place of the default of `rawValue` const adaptableOptions: AdaptableOptions = { exportOptions: { exportDataFormat: 'formattedValue' } } ``` 2. DataFormatDataType Alternatively you can set the `exportDataFormat` property separately for each of the `date`, `number` and `text` Data Types. This is done by returning a [`DataFormatDataType`](https://www.adaptabletools.com/docs/reference/dataformatdatatype.md) object defined as follows: | Property | Type | Description | | --- | --- | --- | | [date](https://www.adaptabletools.com/docs/reference/dataformatdatatype.md#date) | [`DataFormatType`](https://www.adaptabletools.com/docs/reference/dataformattype.md) | Data Format type for Date columns | | [number](https://www.adaptabletools.com/docs/reference/dataformatdatatype.md#number) | [`DataFormatType`](https://www.adaptabletools.com/docs/reference/dataformattype.md) | Data Format type for Number columns | | [text](https://www.adaptabletools.com/docs/reference/dataformatdatatype.md#text) | [`DataFormatType`](https://www.adaptabletools.com/docs/reference/dataformattype.md) | Data Format type for String / Text columns | In this case, all columns with a Data Type specified with `formattedValue` will export display values. ```ts {4} // Set text and number columns to use `formattedValue' const adaptableOptions: AdaptableOptions = { exportOptions: { exportDataFormat: { text: 'formattedValue', date: 'rawValue', // not actually required as this is default value number: 'formattedValue', }, } } ``` - The `exportDateFormat` property has higher precedence than `exportDataFormat` - It will be applied to **all exported Date columns** even if both properties have been set 3. Function returning a DataFormatType The 3rd option is to return a [`DataFormatType`](https://www.adaptabletools.com/docs/reference/dataformattype.md) object but via a function. Every column which the function returns as 'formattedValue' will be exported with its Display Value. The function receives a [`AdaptableColumnContext`](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md) which contains the column to check: | 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 {4} // Set the Format Type to be `formattedValue' for Language column and all numeric columns const adaptableOptions: AdaptableOptions = { exportOptions: { exportDataFormat: (context: AdaptableColumnContext) => { return context.column.dataType == 'number' || context.column.columnId == 'language' ? 'formattedValue' : 'rawValue'; }, } } ``` **Example: Formatting Report Values** Exporting Data using bespoke formatting rules - In this demo we set up export-formatting in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) to export the **formatted** (i.e. display) cell value rather than the underlying value - We have set 3 [Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) in the Grid and in each case the display value is exported: - `Language` column is in upper case - `Created` and `Pushed` columns have a format of 'yyyyMMdd' - All `numeric` columns display 8 digits - Run a Report and notice that the `Language`, `Created`, `Pushed` and `numeric` columns keep the Display Format they were given in Initial State ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Export Formatting', exportOptions: { exportDataFormat: 'formattedValue', }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-language', Scope: {ColumnIds: ['language']}, DisplayFormat: { Formatter: 'StringFormatter', Options: { Case: 'Upper', }, }, }, { Name: 'formatColumn-created_at', Scope: {ColumnIds: ['created_at', 'pushed_at']}, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'yyyyMMdd', }, }, }, { Name: 'formatColumn-number', Scope: {DataTypes: ['number']}, DisplayFormat: { Formatter: 'NumberFormatter', Options: { IntegerDigits: 8, IntegerSeparator: '', }, }, }, ], }, Export: { CurrentReport: 'Current Layout', CurrentFormat: 'Excel', }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'created_at', 'updated_at', 'pushed_at', 'license', 'has_wiki', 'github_watchers', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', 'topics', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ## Formatting Dates Dates can offer additional complexity in terms of formatting export data. It is not unusual that a user will want to export a date differently both to the raw value and to its display value. For this reason AdapTable provides the `exportDateFormat` property in [`Export Options`](https://www.adaptabletools.com/docs/reference/exportoptions.md). ### `exportDateFormat` Custom format for exporting Date columns This property enables you to export **all dates** in a custom format, irrespective of how they are formatted in AG Grid. This property is ignored when running the `VisualExcel` [Report Format Type](https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type/index.md) as it exports the Display Format ```ts {4} // Provide a custom format for date columns const adaptableOptions: AdaptableOptions = { exportOptions: { exportDateFormat: 'yyyy-dd-MM', } } ``` AdapTable exports **all** dates in the custom format provided, irrespective of how they are formatted in AG Grid. - The `exportDateFormat` property has higher precedence than `exportDataFormat` - It will be applied to **all exported Date columns** (including if the column has a valueFormatter) **Example: Formatting Dates in Reports** Exporting data with dates in special format - This demo illustrates how to use the `exportDateFormat` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) to override any formatted dates: - The `Created` and Pushed columns have a Display Format of 'yyyyMMdd' - The `Updated` Column has no Display Format - We have set `exportDateFormat` to 'yyyy-dd-MM' - This takes precedence over the formats used in AG Grid (even though we also set `exportDataFormat` to be *formattedValue*) - Export the data from the Grid and notice that the `Language` column keeps the format it was given in Initial State (since we export display values) - But the `date` columns all use the format giving in Export Options, overriding what is displayed in AG Grid and what formats they have been given ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Export Date Formatting', exportOptions: { exportDateFormat: 'dd-MMM-yyyy', exportDataFormat: 'formattedValue', }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-language', Scope: {ColumnIds: ['language']}, DisplayFormat: { Formatter: 'StringFormatter', Options: { Case: 'Upper', }, }, }, { Name: 'formatColumn-created_at', Scope: {ColumnIds: ['created_at', 'pushed_at']}, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'yyyyMMdd', }, }, }, ], }, Export: { CurrentReport: 'Current Layout', CurrentFormat: 'Excel', }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'created_at', 'updated_at', 'pushed_at', 'license', 'has_wiki', 'github_watchers', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` --- # Processing Reports Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-processing - Developers can "process" (i.e. intercept) a report before it is evaluated and exported - This is used in 3 main use cases: - running the report on the server and sending the data back to AdapTable - cancelling a proposed Export - providing entirely new column and row data All AdapTable reports can be **processed** before they are exported. This allows developers to provide a function implementation enabling them to: - evaluate the Report on the server (typically when using the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md)) - configure whether the Export should take place - provide an entirely different set of report data Processing should be avoided when using the `VisualExcel` Report Format Procesing is configured using the `processExport` property in [`Export Options`](https://www.adaptabletools.com/docs/reference/exportoptions.md) which can return 3 values: - `ExportResultData` object (provided on Server) - will be used as data for Report and exported by AdapTable - `true` - Report will be evaluated by AdapTable as normal, using Grid data (provided by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md)) - `false` - the export will be cancelled and no report will run ### `processExport` Function invoked before a Report is run, enabling users to evaluate on the server or cancel the export Typically AdapTable will take care of all that is required to run a Report and export the data to the specified destination. However sometimes users might want to intercept this process to modify, or provide all, the data themselves. This is most typically the case when using the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) This property enables developers to check what data is about to be exported. If this function is provided, it will be invoked when a Report is run, enabling users to preload the data prior to an export. The function definition is as follows: ```ts processExport?: (processExportContext: ProcessExportContext) => Promise; ``` The function receives a [`processexportcontext`](https://www.adaptabletools.com/docs/reference/processexportcontext.md) object, which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [convertToCsv](https://www.adaptabletools.com/docs/reference/processexportcontext.md#converttocsv) | `(reportData: `[`ReportData`](https://www.adaptabletools.com/docs/reference/reportdata.md)`) => string` | Converts the Report Data to CSV format | | [convertToExcel](https://www.adaptabletools.com/docs/reference/processexportcontext.md#converttoexcel) | `(reportData: `[`ReportData`](https://www.adaptabletools.com/docs/reference/reportdata.md)`) => Blob` | Converts the Report Data to Excel format | | [getReportColumns](https://www.adaptabletools.com/docs/reference/processexportcontext.md#getreportcolumns) | `() => `[`ReportColumn`](https://www.adaptabletools.com/docs/reference/reportcolumn.md)`[]` | Returns Columns to export based on Report's `ReportColumnScope` | | [adaptableContext](https://www.adaptabletools.com/docs/reference/processexportcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | and it can return 3 values: - `ExportResultData` object - will be used as the data for the Report and will be exported by AdapTable - `true` - the Report will be evaluated by AdapTable as normal, using the data from the Grid (provided by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md)) - `false` - the export will be cancelled and no report will run The [`ExportResultData`](https://www.adaptabletools.com/docs/reference/exportresultdata.md) object defines the shape of the returned data: ```ts export type ExportResultData = | { type: 'csv'; data: string; } | { type: 'json'; data: ReportData; } | { type: 'excel'; data: Blob | string; }; ``` The ExportResultData is returned asyncronously via a Promise (and so can the boolean values if required) Cancelling an Export ```ts {4} // Don't allow Current Layout report to be run const adaptableOptions: AdaptableOptions = { exportOptions: { processExport: async (context: ProcessExportContext) => { if (context.report.Name === 'Current Layout') { return false; } }, } } ``` ## Exporting via the Server The most common use case for processing reports is when running **export on the server**. This most typically happens when using the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-exporting/index.md) Developers can evaluate the report on the server, and return the report data to AdapTable for it to export to the selected destination. **Example: Processing: Creating Reports on Server** Report processing to run report on server - This demo illustrates how to use the `processExport` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) to create report data on the Server and return to AdapTable to export - It is taken from the more extensive [Server-Side Row Model Demo](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) focussing purely on Export - Both the (System) 'All Data', and the (Custom) 'US Golden Athletes' Reports are evaluated on the server, and the data is sent back to AdapTable to export - Run the 'All Data' or 'US Golden Athletes' Reports and note how the data is provided 'on the server' and then send back to AdapTable ```ts import { AdaptableColumnBase, AdaptableOptions, ProcessExportContext, Report, ExportResultData, ReportData, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!; interface RequestReportConfig { report: Report; reportColumns: AdaptableColumnBase[]; reportQueryAST?: any; } export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', userName: 'Server-side Demo', adaptableId: 'Process Run on Server', exportOptions: { processExport: async (context: ProcessExportContext) => { const {report, reportFormat} = context; const reportConfig: RequestReportConfig = { report, reportColumns: context.getReportColumns(), }; 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 jsonReportData: ReportData = await serverSideResponse.json(); if (reportFormat === 'JSON') { const serverSideReportData: ExportResultData = { type: 'json', data: jsonReportData, }; return serverSideReportData; } if (reportFormat === 'CSV') { const csvReportData = context.convertToCsv(jsonReportData); const serverSideReportData: ExportResultData = { type: 'csv', data: csvReportData, }; return serverSideReportData; } if (reportFormat === 'Excel' || reportFormat === 'VisualExcel') { const excelReportData = context.convertToExcel(jsonReportData); const serverSideReportData: ExportResultData = { type: 'excel', data: excelReportData, }; return serverSideReportData; } context.adaptableApi.alertApi.showAlertWarning( 'Cannot Run Report', `Report Format ${reportFormat} not supported` ); return false; }, systemReportNames: ['All Data'], }, initialState: { Dashboard: { Tabs: [ { Name: 'Main', Toolbars: ['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: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'athlete', 'gold', 'silver', 'bronze', 'totalMedals', 'country', 'sport', 'year', ], ColumnSizing: { athlete: {Width: 175}, bronze: {Width: 100}, country: {Width: 125}, gold: {Width: 100}, silver: {Width: 100}, sport: {Width: 175}, totalMedals: {Width: 100}, year: {Width: 115}, }, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo, AdaptableApi} from '@adaptabletools/adaptable'; import { ColDef, IServerSideDatasource, IServerSideGetRowsParams, } 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 filters = adaptableApi.filterApi.columnFilterApi.getColumnFilterDefs(); const query = adaptableApi.filterApi.gridFilterApi.getCurrentGridFilterExpression() ?? ''; const gridFilterAST = adaptableApi.expressionApi.getASTForExpression(query); const customSorts = adaptableApi.customSortApi.getActiveCustomSorts(); // enhance sortModel with custom order if present const sortModel = params.request.sortModel.map(sort => { const customSort = customSorts.find( customSort => customSort.ColumnId === sort.colId ); if (customSort) { return { ...sort, sortedValues: customSort.SortedValues, }; } return sort; }); if (gridFilterAST) { console.log('gridFilterAST', gridFilterAST); } const request = { ...params.request, sortModel, adaptableFilters: filters, 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, }); adaptableApi.systemStatusApi.setInfoSystemStatus( `SQL: ${response.sql.slice(0, 40)}`, response.sql ); }) .catch(error => { params.fail(); }); }, }; } ``` ```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, }, ]; ``` ## Cancelling an Export Because the function can return a boolean, this can be leveraged to set whether the proposed Report runs. This allows developers to decide dynamically whether or not the user can run the given report. The boolean value can be returned asynchronously if required, allowing server permission checks **Example: Processing: Stopping Export** Report processing to stop Exports - This demo illustrates how to use the `processExport` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) to stop a particular Report from being run. - We do not allow the `Current Layout` report to be run (and output a System Status Message to that effect) - Run the 'Current Layout' Report and note that the export is prevented (with a System Status Message displayed) - Switch to a different Report and this time the export works as normal ```ts import { AdaptableOptions, ProcessExportContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Process Prevent Export', exportOptions: { processExport: async (context: ProcessExportContext) => { if (context.report.Name === 'Current Layout') { context.adaptableApi.systemStatusApi.setWarningSystemStatus( 'Cannot Run Report' ); return false; } return true; }, }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export', 'SystemStatus'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'Current Layout', CurrentFormat: 'Excel', }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'week_issue_change', 'github_stars', 'created_at', 'updated_at', 'pushed_at', 'license', 'has_wiki', 'github_watchers', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'topics', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` --- # AdapTable Reports Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-reports - AdapTable provides 3 System Reports which can be run at any time - Thes are designed to cover the most common use cases: `All Data`, `Current Layout` and `Selected Data` - System Reports can be exported in various formats to all destinations AdapTable ships with 3 System (i.e. predefined) Reports designed for frequently used exports: | Report | Contains | Cols & Rows | | ---------------- | ------------------------------------------------------------------------- | ----------- | | `All Data` | All Data in Grid's Dataset (i.e. all Rows and Columns) | All | | `Current Layout` | Data in current Layout (i.e. currently filtered Rows and visible Columns) | Visible | | `Selected Data` | Currently selected Grid data (both Cells and Rows) | Selected | Additionally developers and run-time users can create bespoke [Custom Reports](https://www.adaptabletools.com/docs/handbook-exporting-reports-custom/index.md) **Example: Exporting System Reports** Exporting data from AdapTable using System Reports - In this example AdapTable has been set up so that: - the Current Report is the `All Data` System Report - the Report Format is `JSON` - Click the `Export` button in the Export toolbar and select 'Download' to send the report as a `JSON` file ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'System Reports', initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'All Data', CurrentFormat: 'JSON', }, 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, }, ], }, }, }; ``` ### Limiting System Reports By default all 3 System Reports will be shipped with AdapTable and available for use. However this can be changed via the `systemReportNames` property of [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md). The property returns a list (either directly or via a function) of which System Reports should be available. ### `systemReportNames` Sets which System Reports are available for users [`SystemReportNames[]`](https://www.adaptabletools.com/docs/reference/systemreportname.md) Use this property to specify a custom list of the System Reports which should be available to users. You can return either an array of report names, or provide a function which returns an array. Hard Coded List The simplest method is to return an array listing which System Reports should be available: ```ts {4} // Show just 'All Data' and 'Current Layout' System Reports const adaptableOptions: AdaptableOptions = { exportOptions: { systemReportNames: ['All Data', 'Current Layout'], } } ``` Provide an **empty** array if you want **no** System Reports to be available: ```ts {4} // Show No System Reports const adaptableOptions: AdaptableOptions = { exportOptions: { systemReportNames: [], } } ``` Via a Function Alternatively, you can provide a function which returns the System Report Names. The function receives context of type [`SystemReportNamesContext`](https://www.adaptabletools.com/docs/reference/systemreportnamescontext.md) defined as follows: | Property | Type | Description | | --- | --- | --- | | [currentLayoutName](https://www.adaptabletools.com/docs/reference/systemreportnamescontext.md#currentlayoutname) | `string` | Name of current Layout | | [defaultSystemReportNames](https://www.adaptabletools.com/docs/reference/systemreportnamescontext.md#defaultsystemreportnames) | [`SystemReportName`](https://www.adaptabletools.com/docs/reference/systemreportname.md)`[]` | Default System Report Names | | [adaptableContext](https://www.adaptabletools.com/docs/reference/systemreportnamescontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```ts {4} // Show just 'All Data' System Report when in 'Pivot View' Layout const adaptableOptions: AdaptableOptions = { exportOptions: { systemReportNames: (context: SystemReportNamesContext) => { return context.currentLayoutName == 'Pivot View' ? ['All Data'] : context.defaultSystemReportNames; }, } } ``` Developers can supply a list of System Report names to this property and only these reports will be available. - If the `Selected Data` report is removed from System Reports using the function above, the `Export Selected Cells` and `Export Selected Rows` Menu Items in the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) will still remain - Use the properties available in [Context Menu Options](https://www.adaptabletools.com/docs/ui-context-menu-technical-reference/index.md) to remove these menu items completely **Example: Configuring System Reports** Configuring which System Reports are available - In this example AdapTable has been limited to just 2 System Reports: - `All Data` - `Current Layout` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Configuring System Reports', exportOptions: { systemReportNames: ['All Data', 'Current Layout'], }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'All Data', CurrentFormat: 'CSV', }, 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 Reports Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-reports-custom - AdapTable allows users to create Custom Reports - These can be configured by developers at design-time, or build in the UI at run-time - Custom Reports typically use an Expression - Custom Reports can be exported in various formats to all destinations Custom (i.e. bespoke) Reports can be provided to supplement the System Reports shipped by AdapTable. Custom Reports can be created and supplied in 2 ways: - by run-time users via the Export Wizard - at design-time through Export Initial State AdapTable enables these reports to be exported to all available destinations. Each Custom Report specifies which columns and rows to export. Custom Report rows typically contain a [Boolean 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) each time the Report runs **Example: Custom Reports** Exporting Data from AdapTable via Custom-created Reports - This demo contains 2 Custom Reports (provided in Export Initial State): - `Popular Frameworks` - exports 2 columns for rows with `Github Stars` > 50000 - `MIT JavaScript` - exports 5 columns for rows where `Language` is *JavaScript* and the `License` is *MIT License* ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom Reports', initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], ModuleButtons: ['Export', 'SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'Popular Frameworks', CurrentFormat: 'JSON', Reports: [ { Name: 'Popular Frameworks', ReportColumnScope: 'ScopeColumns', ReportRowScope: 'ExpressionRows', Scope: {ColumnIds: ['name', 'language']}, Query: {BooleanExpression: '[github_stars] > 50000 '}, }, { Name: 'MIT JavaScript', ReportColumnScope: 'ScopeColumns', ReportRowScope: 'ExpressionRows', Scope: { ColumnIds: ['name', 'language', 'topics', 'license', 'updated_at'], }, Query: { BooleanExpression: "[language] = 'JavaScript' AND [license] = 'MIT 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, }, ], }, }, }; ``` ### Defining Custom Reports Custom Reports can be provided at design-time in [Export Initial State](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md). ### Defining a Custom Report Follow these steps to define a Custom Report: `ReportColumnScope` defines the Report's **columns**. The available values are: - *AllColumns* - every Column defined in AG Grid GridOptions - *VisibleColumns* - every visible Column in the Grid - *ScopeColumns* - bespoke Column list (defined separately) ```ts {5} const initialState: InitialState = { Export: { Reports: [ { ReportColumnScope: 'ScopeColumns', ReportRowScope: 'ExpressionRows', Scope: {ColumnIds: ['name', 'language']}, Query: {BooleanExpression: '[github_stars]>50000'}, Name: 'Popular Frameworks', }, ], }, } ``` If `ReportColumnScope` is set to *ScopeColumns*, then these must be listed separately in the `Scope` property. This defines **which** Columns, Column Types or Data Types will be exported. ```ts {7} const initialState: InitialState = { Export: { Reports: [ { ReportColumnScope: 'ScopeColumns', ReportRowScope: 'ExpressionRows', Scope: {ColumnIds: ['name', 'language']}, Query: {BooleanExpression: '[github_stars]>50000'}, Name: 'Popular Frameworks', }, ], }, } ``` See [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) for a detailed look at this commonly used object `ReportRowScope` defines the Report's **rows**. The available values are: - *AllRows* - every Row in AG Grid's data source - *VisibleRows* - Rows currently in Grid (if not viewport) - *ExpressionRows* - Rows returned by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) Query (see below) ```ts {6} const initialState: InitialState = { Export: { Reports: [ { ReportColumnScope: 'ScopeColumns', ReportRowScope: 'ExpressionRows', Scope: {ColumnIds: ['name', 'language']}, Query: {BooleanExpression: '[github_stars]>50000'}, Name: 'Popular Frameworks', }, ], }, } ``` If `ReportRowScope` is set to *ExpressionRows*, then the `Query` property must also be provided. This contains the [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) which will be evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) each time the Report is run. ```ts {8} const initialState: InitialState = { Export: { Reports: [ { ReportColumnScope: 'ScopeColumns', ReportRowScope: 'ExpressionRows', Scope: {ColumnIds: ['name', 'language']}, Query: {BooleanExpression: '[github_stars]>50000'}, Name: 'Popular Frameworks', }, ], }, } ``` Rows exported via a query do not need to be visible in the Grid when the Report runs, but do need to be in the underlying Data Set Provide a unique, and easily identifiable name for the Report via the `Name` property. This value will be used wherever the Report is referenced, e.g. in the Toolbar, Tool Panel or Export section of the Settings Panel. ```ts {9} const initialState: InitialState = { Export: { Reports: [ { ReportColumnScope: 'ScopeColumns', ReportRowScope: 'ExpressionRows', Scope: {ColumnIds: ['name', 'language']}, Query: {BooleanExpression: '[github_stars]>50000'}, Name: 'Popular Frameworks', }, ], }, } ``` ### Using Custom Report Wizard ### Using the Export Wizard to Create / Edit Custom Reports There are a few steps required for creating a Custom Report in the Export Wizard: Select whether the Report should display: - *All Columns* - every Column defined in AG Grid GridOptions - *Visible Columns* - every visible Column in the Grid - *Bespoke Columns* - a custom Column (or DataType) list If "Bespoke Columns" was selected in the previous step the Scope Component is displayed. Here you can specify which Columns or DataTypes to export. See Scope for a detailed look at this commonly used object Select whether the Report should export: - *All Rows* - every Row in AG Grid's data source - *Visible Rows* - Rows currently in Grid (though not necessarily in the viewport) - *By Query* - only the Rows returned by an AdapTableQL Query If "By Query" was selected in previous step, the Expression Editor is displayed. This allows you to create a powerful, custom Boolean Expression. This will then be evaluated by AdapTableQL each time the Report is run. Rows exported via a query need to be in the Data Set (but not the Grid) when the Report runs See [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) for in-depth information on running Queries Provide a unique, and easily identifiable name for the Custom Report via the `Name` property. This value will be used wherever the Report is referenced, e.g. in the Toolbar, ToolPanel or Export section of the Settings Panel. --- # Report Format Types Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type - AdapTable ships with 4 Report Format Types that can be used to format Report data: - Excel - VisualExcel - JSON - CSV Reports in AdapTable can be exported using 4 different Report Format Types: - `Excel` - `VisualExcel` - `JSON` - `CSV` 2 Format Types (JSON, CSV) export to File and Clipboard, and 2 (Excel, VisualExcel) just to File: | Report Format | All Reports | Exports to File | Exports to Clipboard | | ------------- | :---------: | :-------------: | :------------------: | | [Excel](https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type-excel/index.md) | ✅ | ✅ | ❌ | | [Visual Excel](https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type-visual-excel/index.md) | ✅ | ✅ | ❌ | | `JSON` | ✅ | ✅ | ✅ | | `CSV` | ✅ | ✅ | ✅ | ## Limiting System Report Formats By default all System Report Format Types will be shipped with AdapTable and available for use. However this can be changed via the `systemReportFormats` property of [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md). The property returns a list (either directly or via a function) of which System Report Formats should be available. ### `systemReportFormats` Sets which System Report Formats are available for users [`SystemReportFormat[]`](https://www.adaptabletools.com/docs/reference/systemreportformat.md) Use this property to specify a custom list of the System Report Formats which should be available to users. You can return either an array of report formats, or provide a function which returns an array. Hard Coded List The simplest method is to return an array listing which System Report Formats should be available: ```ts {4} // Show just 'CSV' and 'JSON' System Report Formats const adaptableOptions: AdaptableOptions = { exportOptions: { systemReportFormats: ['CSV', 'JSON'], } } ``` Provide an **empty** array if you want **no** System Report Formats to be available: ```ts {4} // Show No System Report Formats const adaptableOptions: AdaptableOptions = { exportOptions: { systemReportFormats: [], } } ``` Via a Function Alternatively, you can provide a function which returns the System Report Formats. The function receives context of type [`SystemReportFormatsContext`](https://www.adaptabletools.com/docs/reference/systemreportformatscontext.md) defined as follows: | Property | Type | Description | | --- | --- | --- | | [currentLayoutName](https://www.adaptabletools.com/docs/reference/systemreportformatscontext.md#currentlayoutname) | `string` | Name of current Layout | | [currentReportName](https://www.adaptabletools.com/docs/reference/systemreportformatscontext.md#currentreportname) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md) | Name of current Report | | [defaultSystemReportFormats](https://www.adaptabletools.com/docs/reference/systemreportformatscontext.md#defaultsystemreportformats) | [`SystemReportFormat`](https://www.adaptabletools.com/docs/reference/systemreportformat.md)`[]` | Default System Report Formats | | [adaptableContext](https://www.adaptabletools.com/docs/reference/systemreportformatscontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```ts {4} // Show just JSON and CSV Report Formats for 'All Data' System Report const adaptableOptions: AdaptableOptions = { exportOptions: { systemReportFormats: (context: SystemReportFormatsContext) => { return context.currentReportName == 'All Data' ? ['JSON', 'CSV'] : context.defaultSystemReportFormats; }, } } ``` **Example: Configuring System Report Formats** Configuring which System Report Formats are available - In this example AdapTable has been limited to just 2 System Report Formats: - `JSON` - `CSV` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Configuring System Report Formats', exportOptions: { systemReportFormats: ['CSV', 'JSON'], }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentReport: 'All Data', CurrentFormat: 'CSV', }, 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, }, ], }, }, }; ``` --- # Report Format Type - CSV Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type-csv - AdapTable offers a CSV Report Format which allows grid data to be exported in CSV format Reports can be given a Report Format of CSV. CSV formatted Reports can be exported to all destinations. ## CSV Separator By default AdapTable will use a comma (',') to separate the values, but this can be changed by developers using the `csvSeparator` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md). ### `csvSeparator` Separator to use in CSV format This property allows developers to change the default CSV separator value of a comma. The property can return either a string, or function which takes a [`BaseExportContext`](https://www.adaptabletools.com/docs/reference/baseexportcontext.md) object and returns a string. ```ts csvSeparator?: string | ((csvSeparatorContext: BaseExportContext) => string); ``` The `BaseExportContext` contains these properties: | Property | Type | Description | | --- | --- | --- | | [exportDestination](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#exportdestination) | [`ExportDestinationType`](https://www.adaptabletools.com/docs/reference/exportdestinationtype.md) | Export Destination for the Report | | [report](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#report) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md) | The Report Configuration being run | | [reportFormat](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#reportformat) | [`ReportFormatType`](https://www.adaptabletools.com/docs/reference/reportformattype.md) | Format of the Report being run | | [reportName](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#reportname) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md) | Name of the Report being run | | [adaptableContext](https://www.adaptabletools.com/docs/reference/baseexportcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```ts {4} // Use a pipe to separate values in the CSV file const adaptableOptions: AdaptableOptions = { exportOptions: { csvSeparator: '|' } } ``` **Example: CSV Report Format** Exporting Data from AdapTable in CSV Format - This demo sets the Current Report Format in Initial State to CSV, and changed the CSV separator to be a '|' - Exporting a report will send the data in CSV format with the custom delimiter ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'CSV Report Format', exportOptions: { csvSeparator: '|', }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], ModuleButtons: ['Export', 'SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentFormat: 'CSV', }, 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, }, ], }, }, }; ``` --- # Report Format Type - Excel Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type-excel The most commonly used Report Format Type is `Excel`, where the exported data can be opened in Excel. This option is only available if the `ExcelExportModule` [AG Grid Module](https://www.adaptabletools.com/docs/getting-started-aggrid-modules/index.md) is loaded When using this option only the downloadable File [System Export Destination](https://www.adaptabletools.com/docs/handbook-exporting-destinations/index.md) is available (i.e. the data cannot be sent to the Clipboard). Users **are** able to create a [Custom Export Destination](https://www.adaptabletools.com/docs/handbook-exporting-destinations-custom/index.md), e.g S3, and then export the Excel formatted data there ## Excel Column Types AdapTable allows developers to define in AG Grid, columns which have a particular Excel Data Type. This ensures that Excel will render that column using the correct type. - This only affects the behaviour in Excel for exported data - There is no impact on how AdapTable (or AG Grid) renders the Column or formats the Cells There are 4 types of Column Data Types supported - `numberExcelType` - `stringExcelType` - `dateExcelType` - `booleanExcelType` This are configured using the `cellClass` property in the `ColDefs` object (which is an array), e.g: ``` cellClass: ["stringExcelType"] ``` This can very occasionally result in the column losing any formatting which it has been given in AdapTable **Example: Excel Column Type** Exporting to Excel using Excel Column Types (to preserve formatting) - In this example we configure 2 Columns with Excel Column Types: - `Rating` - has a `stringExcelType` - `Price` - has a `numberExcelType` - Export to Excel and note that the `Price` column is of type Number and the `Rating` column shows all values as strings ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {Car} from './rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'model', adaptableId: 'Excel Column Types', initialState: { Theme: {CurrentTheme: 'dark'}, Dashboard: { PinnedToolbars: ['Export'], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'make', 'model', 'made', 'available', 'pricePerMile', 'rating', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {GridOptions, themeBalham} from 'ag-grid-enterprise'; import {columnDefs} from './columnDefs'; import {rowData, Car} from './rowData'; export const gridOptions: GridOptions = { theme: themeBalham, defaultColDef: { resizable: true, sortable: true, editable: true, filter: true, floatingFilter: true, }, columnDefs: columnDefs, rowData: rowData.map(data => { return { ...data, made: data.made.toISOString() as any, }; }), 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'; import {Car} from './rowData'; export const columnDefs: ColDef[] = [ { headerName: 'Make', field: 'make', filter: true, editable: false, enableRowGroup: true, enablePivot: true, cellDataType: 'text', }, { headerName: 'Model', field: 'model', filter: true, editable: false, cellDataType: 'text', }, { headerName: 'Price', field: 'pricePerMile', filter: true, editable: false, cellDataType: 'number', cellClass: ['numberExcelType'], }, { headerName: 'Made', field: 'made', // valueGetter: params => { // return params.data?.made?.toISOString(); // }, filter: true, editable: false, cellDataType: 'date', cellClass: ['dateExcelType'], }, { headerName: 'Available', field: 'available', filter: true, editable: true, cellDataType: 'boolean', }, { headerName: 'Rating', field: 'rating', editable: true, sortable: true, cellDataType: 'text', cellClass: ['stringExcelType'], filter: true, resizable: true, }, ]; ``` ```ts export interface Car { make: string; model: string; made: Date; available: boolean; pricePerMile: number; rating: string; } export const rowData: Car[] = [ { make: 'Toyota', model: 'Celica', made: new Date(2017, 11, 4), available: true, pricePerMile: 21.345676, rating: '001', }, { make: 'Ford', model: 'Focus', made: new Date(2017, 3, 3), available: false, pricePerMile: 31.2432432423, rating: 'A3', }, { make: 'Toyota', model: 'Yaris', made: new Date(2013, 1, 15), available: true, pricePerMile: 29.32432423, rating: '003', }, { make: 'Toyota', model: 'Corolla', made: new Date(2017, 6, 9), available: false, pricePerMile: 32.9032523473287, rating: '005', }, { make: 'Ford', model: 'Mondeo', made: new Date(2009, 10, 2), available: true, pricePerMile: 28.247893473289, rating: 'A2', }, { make: 'Ford', model: 'Fiesta', made: new Date(2018, 8, 12), available: false, pricePerMile: 34.0001, rating: 'A5', }, { make: 'Porsche', model: 'Boxter', made: new Date(2016, 1, 28), available: true, pricePerMile: 32.29580292, rating: '004', }, { make: 'Ford', model: 'Galaxy', made: new Date(2015, 4, 14), available: false, pricePerMile: 29.29432404, rating: 'A2', }, { make: 'Porsche', model: 'Mission', made: new Date(2008, 10, 7), available: false, pricePerMile: 35.7822957, rating: '005', }, { make: 'Mitsubbishi', model: 'Outlander', made: new Date(2017, 11, 14), available: true, pricePerMile: 19.224309, rating: '004', }, ]; ``` --- # Report Format Type - JSON Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type-json - AdapTable offers a JSON Report Format which allows grid data to be exported in JSON format Reports can be given a Report Format of JSON. JSON formatted Reports can be exported to all destinations. **Example: JSON Report Format** Exporting Data from AdapTable in JSON Format - This demo sets the Current Report Format in Initial State to JSON - Exporting a report will send the data in JSON format ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'JSON Report Format', initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export'], }, ], ModuleButtons: ['Export', 'SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { CurrentFormat: 'JSON', }, 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, }, ], }, }, }; ``` --- # Report Format Types - Visual Excel Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type-visual-excel Reports in AdapTable are not WYSIWYG (What You See is What You Get). It is the Grid's underlying raw data, rather than display values, styles or grouping, which is exported. - Developers do, however, have some control over the [Formatting of other Reports](https://www.adaptabletools.com/docs/handbook-exporting-formatting-reports/index.md) - They can set how to format dates and choose between exporting cell *raw* (the default) or *display* values The one exception to this "data-only" rule is the `VisualExcel` Report Format Type. This exports Columns that contain styles so that they appear in Excel the same way as they do in AdapTable. The `VisualExcel` Report Format Type includes the following elements: - defined in **AG Grid**: - Value Getters - Cell Formatters - defined in **AdapTable**: - [Formatted Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) (which contain [AdapTable Styles](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md)) - [Row Groups](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md) ## Exporting Styles AdapTable will export styles that have been created in AG Grid or AdapTable into Excel format. This means that if there are any [AG Grid Excel Styles](https://www.ag-grid.com/javascript-data-grid/excel-export-styles/) defined, Adaptable will try to render them. Any [AdapTable Styles](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md) defined with the Format Column will **always take precedence** over AG Grid styles - We recommend using AdapTable's versatile [Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) instead of AG Grid's standard value formatters - It offers ingrained styling support for Excel and ensures the Format Column definition is the *sole source of truth* **Example: VisualExcel Report Format Type** Using the VisualExcel Report Format Type for a WYSIWYG export - In this example AdapTable has been set to use the `VisualExcel` Report Format Type (and `Current Layout` report) - We added a number of features which all get included in the Export: - [Column Formats that use AdapTable Styles](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md) - [Gradient Styled Column](https://www.adaptabletools.com/docs/handbook-styled-column-gradient/index.md) - [Grand Total Row](https://www.adaptabletools.com/docs/handbook-aggregation-grand-total-row/index.md) - Switch to `Grouped Layout` - note how the [Column Formats](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) are preserved ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'VisualExcel Report Format', initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['Export', 'Layout'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export', 'Layout'], }, ], }, Export: { CurrentReport: 'Current Layout', CurrentFormat: 'VisualExcel', }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-github_stars', Rule: { Predicates: [ { PredicateId: 'GreaterThan', Inputs: [10000], }, ], }, Scope: { ColumnIds: ['github_stars'], }, Style: { BackColor: 'Yellow', }, }, { Name: 'formatColumn-name', Scope: { ColumnIds: ['name'], }, Style: { BackColor: 'Brown', ForeColor: 'White', }, }, { Name: 'formatColumn-license', Scope: { ColumnIds: ['license'], }, Style: { FontStyle: 'Italic', }, }, ], }, StyledColumn: { StyledColumns: [ { Name: 'github_watchers Gradient', ColumnId: 'github_watchers', GradientStyle: { RangeValueType: 'Number', CellRanges: [{Min: 'Col-Min', Max: 'Col-Max', Color: '#a52a2a'}], }, }, ], }, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'license', 'github_watchers', 'has_projects', 'has_pages', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'week_issue_change', ], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'week_issue_change', AggFunc: 'min', }, ], Name: 'Standard Layout', AutoSizeColumns: true, GrandTotalRow: 'top', }, { TableColumns: [ 'name', 'language', 'github_stars', 'license', 'github_watchers', 'has_projects', 'has_pages', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'week_issue_change', ], RowGroupedColumns: ['language'], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'week_issue_change', AggFunc: 'min', }, ], Name: 'Grouped Layout', AutoSizeColumns: true, GrandTotalRow: 'bottom', }, ], }, }, }; ``` ## Exporting Formats The `VisualExcel` Report Format **always** exports any Display Formats currently rendered in AdapTable. - The `exportDataFormat` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) evaluates whether to export raw value or display value - But (only) the `VisualExcel` Report Format Type ignores this since it **only** exports display values ## Exporting Excel Dates When using the `VisualExcel` Report Format Type, Date columns can be explicitly exported as Excel Date cells. This means that Excel will see the Column as a Date and treat it as such when providing Filters and other functionality To achieve this, the following are required: - the Column has a [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) of `date` - a custom Date format is provided. This can be either: - set using the (global) `exportDateFormat` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md); or - via the `exportDataFormat` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) which is set to `formattedValue` for Dates This option also requires the Column to have an active [Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) using [`DateFormatterOptions`](https://www.adaptabletools.com/docs/reference/dateformatteroptions.md) ## Exporting Styled Columns The `VisualExcel` Report Format Type will only export the [Gradient Style](https://www.adaptabletools.com/docs/handbook-styled-column-gradient/index.md) Styled Column. This is because it simply contains a back colour which is easy to send to Excel. The `VisualExcel` Report Format Type will **not** export [Percent Bar](https://www.adaptabletools.com/docs/handbook-styled-column-percent-bar/index.md) or [Badge](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md) or [Sparkline Column](https://www.adaptabletools.com/docs/handbook-styled-column-sparkline/index.md) Styled Columns --- # Scheduling Reports in AdapTable Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-scheduling - Scheduling in AdapTable allows Reports to be run at a chosen time - Report schedules are stored in `Export.ReportSchedules` and managed from the Export module AdapTable allows you to **schedule** [Reports](https://www.adaptabletools.com/docs/handbook-exporting/index.md) to be sent at specific times and days. Each schedule uses one of two timing models: - **Recurring** — a standard 5-field `CronExpression` (e.g. weekdays at 09:30 → `30 9 * * 1-5`) - **One-off** — a single run at a specified ISO datetime This is useful if you need regularly to export data at a particular time, e.g. an "End of Day" report When configuring a Schedule you will select 4 element: - Report (System or Custom) - Report Format - Destination (System or Custom) - Schedule (recurring or one-off) - Prior to [Version 23.0](https://www.adaptabletools.com/support/version-230-release-note) Schedules were stored in a separate Schedule section of State - Now the `ReportSchedules` section in Export State persists them to ensure everything report related is ine one place **Example: Schedules** Scheduling Reports in AdapTable - This example provides two Report Schedules in Export Initial State: - **Weekday Excel export** — recurring cron (`30 17 * * 1-5`) for the *Current Layout* system report - **One-off CSV export** — runs once (~1 minute after load) for the *JavaScript Frameworks* [Custom Report](https://www.adaptabletools.com/docs/handbook-exporting-reports-custom/index.md) - We listen to the [Report Schedule Ran Event](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) and output an appropriate [System Status Message](https://www.adaptabletools.com/docs/handbook-system-status-message/index.md) - Edit the weekday schedule and change the cron time or destination - Suspend the one-off schedule before it fires if you do not want a download ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; const nowMinutes = new Date().getMinutes(); export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Report Schedules', initialState: { Dashboard: { ModuleButtons: ['Export'], PinnedToolbars: ['Export', 'SystemStatus'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Export: { Reports: [ { Name: 'JavaScript Frameworks', ReportColumnScope: 'AllColumns', ReportRowScope: 'ExpressionRows', Query: { BooleanExpression: '[language] = "JavaScript"', }, }, ], ReportSchedules: [ { Name: 'Weekday Excel export', ReportName: 'Current Layout', ReportFormat: 'Excel', ExportDestination: 'Download', Schedule: { IsOneOff: false, CronExpression: '30 17 * * 1-5', }, }, { Name: 'One-off CSV export', ReportName: 'JavaScript Frameworks', ReportFormat: 'CSV', ExportDestination: 'Download', Schedule: { IsOneOff: true, RunAt: (() => { const d = new Date(); d.setMinutes(nowMinutes + 1, 0, 0); return d.toISOString(); })(), }, }, ], }, 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, ReportScheduleRanInfo } from '@adaptabletools/adaptable'; export const onAdaptableReady = (info: AdaptableReadyInfo) => { info.adaptableApi.eventApi.on( 'ReportScheduleRan', (eventInfo: ReportScheduleRanInfo) => { const reportSchedule = eventInfo.reportSchedule; const scheduleName = reportSchedule?.Name ?? 'Report schedule'; const reportName = reportSchedule?.ReportName ?? 'report'; const ranAt = "JW TODO";// new Date(eventInfo.RanAt).toLocaleString(); info.adaptableApi.systemStatusApi.setSuccessSystemStatus( `${scheduleName}: ${reportName} export ran`, `Triggered at ${ranAt}` ); } ); }; ``` ## Configuring Report Schedules Report Schedules are defined, and persisted, in the `ReportSchedules` section of [Export Initial State](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md). ### Anatomy of a Report Schedule The [`ReportSchedule`](https://www.adaptabletools.com/docs/reference/reportschedule.md) object contains information about the object being scheduled and is defined as follows: | Property | Type | Description | | --- | --- | --- | | [ExportDestination](https://www.adaptabletools.com/docs/reference/reportschedule.md#exportdestination) | [`ExportDestinationType`](https://www.adaptabletools.com/docs/reference/exportdestinationtype.md) | Destination of Report to run on Schedule | | [Name](https://www.adaptabletools.com/docs/reference/reportschedule.md#name) | `string` | Unique display name for this scheduled report | | [ReportFormat](https://www.adaptabletools.com/docs/reference/reportschedule.md#reportformat) | [`ReportFormatType`](https://www.adaptabletools.com/docs/reference/reportformattype.md) | Format of Report to run on Schedule | | [ReportName](https://www.adaptabletools.com/docs/reference/reportschedule.md#reportname) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md) | Name of Report to export | | [Schedule](https://www.adaptabletools.com/docs/reference/reportschedule.md#schedule) | [`Schedule`](https://www.adaptabletools.com/docs/reference/schedule.md) | When the export should run | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/reportschedule.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | [IsSuspended](https://www.adaptabletools.com/docs/reference/reportschedule.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object | The actual scheduling is provided in the [`Schedule`](https://www.adaptabletools.com/docs/reference/schedule.md) object, which is defined as follows: | 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 | ### Providing Report Schedules in Export State Report Schedules are defined in **`Export.ReportSchedules`** in Initial State (alongside custom `Reports`). Each [`ReportSchedule`](https://www.adaptabletools.com/docs/reference/reportschedule.md) needs a display `Name`, the `ReportName` to export, `ReportFormat`, optional `ExportDestination`, and a nested [`Schedule`](https://www.adaptabletools.com/docs/reference/schedule.md) object. The Export section will create the Report Schedule Definitions Supply these properties to provide details of what is scheduled: - `Name` — a unique name for the Schedule - `ReportName` — the Report being exported in the Schedule - `ReportFormat` — Format Type of the Report being exported - `ExportDestination` — where the Scheduled report will be sent Set `Schedule.IsOneOff` to `false` and provide a **5-field cron** string: `minute hour day-of-month month day-of-week`. Example: `30 17 * * 1-5` runs at **17:30 on weekdays** (Monday–Friday). Set `Schedule.IsOneOff` to `true` and `Schedule.RunAt` to an **ISO datetime** (local time) for the single run. ```ts [[1, 2, "Export"], [1, 3, "ReportSchedules"], [2, 5, "Name"], [2, 6, "ReportName"], [2, 7, "ReportFormat"], [2, 8, "ExportDestination"], [2, 15, "Name"], [2, 16, "ReportName"], [2, 17, "ReportFormat"], [2, 18, "ExportDestination"], [3, 9, "Schedule"], [3, 10, "IsOneOff"], [3, 11, "CronExpression"], [4, 19, "Schedule"], [4, 20, "IsOneOff"], [4, 21, "RunAt"]] const initialState: InitialState = { Export: { ReportSchedules: [ { Name: 'Weekday Excel export', ReportName: 'Current Layout', ReportFormat: 'Excel', ExportDestination: 'Download', Schedule: { IsOneOff: false, CronExpression: '30 17 * * 1-5', }, }, { Name: 'One-off CSV export', ReportName: 'JavaScript Frameworks', ReportFormat: 'CSV', ExportDestination: 'Download', Schedule: { IsOneOff: true, RunAt: '2026-05-19T17:30:00.000Z', }, }, ], }, }; ``` For a one-off run 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 Schedules in the UI Report schedules are displayed in the Schedules Tab in the Export section of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md). Additionally there is a Schedule button in the Export Toolbar, Tool Panel and Status Bar The Schedules Tab allows you to: - open the Wizard to create / edit Schedules - suspend or unsuspend Schedules - delete Report Schedules - Deleting a **custom report** also removes every `ReportSchedule` whose `ReportName` matches that report - The UI asks for confirmation when schedules would be removed ### Scheduling a Report in the Export Wizard Use **Export** → **Schedules** tab → **New Schedule** (or create / edit an existing schedule): Choose 3 properties for the schedule: - **Report** (if you clicked New in the Export popup) - **Name** - **Report Format** - **Export Destination** The report being scheduled is shown at the top of this step. Choose which type of Schedule you want: - **Recurring**: pick a preset (e.g. Weekdays, Monthly) or **Custom** and enter a cron expression; set hour and minute - **One-off**: pick the date and time for the single run (`RunAt`) - If the Destination is a Custom one that requires a Form, AdapTable displays it when the scheduled Report runs - The wizard includes an optional **Tags** step which allows Schedules to be included in Extended Layouts ## Report Schedule Ran Event The [Report Schedule Ran Event](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) is triggered when a report schedule runs. The event payload includes full details of the Report that was run on the Schedule. --- # Export Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-exporting-technical-reference - The Live Data Changed Event is fired when data is changed in a Live Report (e.g. ipushpull) - The Export API contains functions to manage exporting and reports programmatically ------------------- ## Export State The [`Export`](https://www.adaptabletools.com/docs/reference/exportstate.md) section of [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) contains details of the current Report and Report Format Type, and a collection of User-provided `Report` objects: | Property | Type | Description | | --- | --- | --- | | [CurrentFormat](https://www.adaptabletools.com/docs/reference/exportstate.md#currentformat) | [`ReportFormatType`](https://www.adaptabletools.com/docs/reference/reportformattype.md) | Selected Report Format - in Export Toolbar & Tool Panel | | [CurrentReport](https://www.adaptabletools.com/docs/reference/exportstate.md#currentreport) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md) | Selected Report Type - in Export Toolbar & Tool Panel | | [Reports](https://www.adaptabletools.com/docs/reference/exportstate.md#reports) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md)`[]` | User-created Reports; each has Name and Row and Column Scope | | [ReportSchedules](https://www.adaptabletools.com/docs/reference/exportstate.md#reportschedules) | [`ReportSchedule`](https://www.adaptabletools.com/docs/reference/reportschedule.md)`[]` | Scheduled Exports for System and Custom Reports | ### Report The [`Report`](https://www.adaptabletools.com/docs/reference/report.md) object is defined as follows: | Property | Type | Description | | --- | --- | --- | | [Name](https://www.adaptabletools.com/docs/reference/report.md#name) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md) | Name of the Report as displayed in the Export toolbar and tool panel | | [Query](https://www.adaptabletools.com/docs/reference/report.md#query) | [`AdaptableBooleanQuery`](https://www.adaptabletools.com/docs/reference/adaptablebooleanquery.md) | Query to use; only required if `ReportRowScope` is 'ExpressionRows' | | [ReportColumnScope](https://www.adaptabletools.com/docs/reference/report.md#reportcolumnscope) | [`ReportColumnScope`](https://www.adaptabletools.com/docs/reference/reportcolumnscope.md) | Columns to display: `AllColumns`, `VisibleColumns`, `SelectedColumns`, `ScopeColumns` | | [ReportRowScope](https://www.adaptabletools.com/docs/reference/report.md#reportrowscope) | [`ReportRowScope`](https://www.adaptabletools.com/docs/reference/reportrowscope.md) | Rows to export: `AllRows`, `VisibleRows`, `SelectedRows`, `ExpressionRows` | | [Scope](https://www.adaptabletools.com/docs/reference/report.md#scope) | [`ColumnScope`](https://www.adaptabletools.com/docs/reference/columnscope.md) | Columns Scope; only required if `ReportColumnScope` is 'ScopeColumns' | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/report.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | ### Schedules The [`ReportSchedule`](https://www.adaptabletools.com/docs/reference/reportschedule.md) object contains information about the object being scheduled and is defined as follows: | Property | Type | Description | | --- | --- | --- | | [ExportDestination](https://www.adaptabletools.com/docs/reference/reportschedule.md#exportdestination) | [`ExportDestinationType`](https://www.adaptabletools.com/docs/reference/exportdestinationtype.md) | Destination of Report to run on Schedule | | [Name](https://www.adaptabletools.com/docs/reference/reportschedule.md#name) | `string` | Unique display name for this scheduled report | | [ReportFormat](https://www.adaptabletools.com/docs/reference/reportschedule.md#reportformat) | [`ReportFormatType`](https://www.adaptabletools.com/docs/reference/reportformattype.md) | Format of Report to run on Schedule | | [ReportName](https://www.adaptabletools.com/docs/reference/reportschedule.md#reportname) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md) | Name of Report to export | | [Schedule](https://www.adaptabletools.com/docs/reference/reportschedule.md#schedule) | [`Schedule`](https://www.adaptabletools.com/docs/reference/schedule.md) | When the export should run | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/reportschedule.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | [IsSuspended](https://www.adaptabletools.com/docs/reference/reportschedule.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object | The actual scheduling is provided in the [`Schedule`](https://www.adaptabletools.com/docs/reference/schedule.md) object, which is defined as follows: | 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 | --------------------- ## Export Options The [`Export Options`](https://www.adaptabletools.com/docs/reference/exportoptions.md) section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) contains these properties: | Property | Type | Description | Default | | --- | --- | --- | --- | | [appendFileTimestamp](https://www.adaptabletools.com/docs/reference/exportoptions.md#appendfiletimestamp) | `boolean` | Whether to add a timestamp as a suffix to exported file name | false | | [csvSeparator](https://www.adaptabletools.com/docs/reference/exportoptions.md#csvseparator) | `string \| ((csvSeparatorContext: `[`BaseExportContext`](https://www.adaptabletools.com/docs/reference/baseexportcontext.md)`) => string)` | Separator for CSV exports | ',' | | [customDestinations](https://www.adaptabletools.com/docs/reference/exportoptions.md#customdestinations) | [`CustomDestination`](https://www.adaptabletools.com/docs/reference/customdestination.md)`[] \| ((context: `[`CustomDestinationsContext`](https://www.adaptabletools.com/docs/reference/customdestinationscontext.md)`) => `[`CustomDestination`](https://www.adaptabletools.com/docs/reference/customdestination.md)`[])` | User-provided Report Destinations (in addition to those shipped in AdapTable) | | | [excelSheetName](https://www.adaptabletools.com/docs/reference/exportoptions.md#excelsheetname) | `string \| ((excelSheetNameContext: `[`BaseExportContext`](https://www.adaptabletools.com/docs/reference/baseexportcontext.md)`) => string)` | Provides a custom name for the Excel sheet when exporting to Excel | 'Sheet 1' | | [exportDataFormat](https://www.adaptabletools.com/docs/reference/exportoptions.md#exportdataformat) | [`DataFormatType`](https://www.adaptabletools.com/docs/reference/dataformattype.md)` \| `[`DataFormatDataType`](https://www.adaptabletools.com/docs/reference/dataformatdatatype.md)` \| ((context: `[`ExportDataFormatContext`](https://www.adaptabletools.com/docs/reference/exportdataformatcontext.md)`) => `[`DataFormatType`](https://www.adaptabletools.com/docs/reference/dataformattype.md)`)` | Sets 'rawValue' or 'formattedValue' as Data format in Reports; can be set for whole grid, per Data Type, or per Column (via a function) | rawValue | | [exportDateFormat](https://www.adaptabletools.com/docs/reference/exportoptions.md#exportdateformat) | `string \| ((context: `[`ExportDateFormatContext`](https://www.adaptabletools.com/docs/reference/exportdateformatcontext.md)`) => string)` | Optional custom format for Date columns when exporting | undefined | | [getDetailRows](https://www.adaptabletools.com/docs/reference/exportoptions.md#getdetailrows) | `(context: `[`GetDetailRowsContext`](https://www.adaptabletools.com/docs/reference/getdetailrowscontext.md)`) => CsvDetailRow[] \| ExcelDetailRow[] \| undefined` | Function to provide the Detail Rows when exporting in Master-Detail grids. This function will be invoked for each master row node. | | | [isColumnExportable](https://www.adaptabletools.com/docs/reference/exportoptions.md#iscolumnexportable) | `(context: `[`AdaptableColumnContext`](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md)`) => boolean` | Whether a Column is included in System Reports and available in UI for selection | true | | [processExport](https://www.adaptabletools.com/docs/reference/exportoptions.md#processexport) | `(processExportContext: `[`ProcessExportContext`](https://www.adaptabletools.com/docs/reference/processexportcontext.md)`) => Promise<`[`ExportResultData`](https://www.adaptabletools.com/docs/reference/exportresultdata.md)` \| boolean>` | Provides custom handling of the Export process before the default export is executed. | | | [reportFilename](https://www.adaptabletools.com/docs/reference/exportoptions.md#reportfilename) | `(reportFileNameContext: `[`ReportFileNameContext`](https://www.adaptabletools.com/docs/reference/reportfilenamecontext.md)`) => string` | Provide a bespoke file name for the Report | | | [skipColumnHeaders](https://www.adaptabletools.com/docs/reference/exportoptions.md#skipcolumnheaders) | `boolean \| ((skipColumnHeadersContext: `[`BaseExportContext`](https://www.adaptabletools.com/docs/reference/baseexportcontext.md)`) => boolean)` | Whether to exclude Column Headers from the exported data | false | | [systemExportDestinations](https://www.adaptabletools.com/docs/reference/exportoptions.md#systemexportdestinations) | [`SystemExportDestination`](https://www.adaptabletools.com/docs/reference/systemexportdestination.md)`[] \| ((context: `[`SystemExportDestinationsContext`](https://www.adaptabletools.com/docs/reference/systemexportdestinationscontext.md)`) => `[`SystemExportDestination`](https://www.adaptabletools.com/docs/reference/systemexportdestination.md)`[])` | Export destinations to use; leave unset for all, empty array for none | 'Download', 'Clipboard' | | [systemReportFormats](https://www.adaptabletools.com/docs/reference/exportoptions.md#systemreportformats) | [`SystemReportFormat`](https://www.adaptabletools.com/docs/reference/systemreportformat.md)`[] \| ((context: `[`SystemReportFormatsContext`](https://www.adaptabletools.com/docs/reference/systemreportformatscontext.md)`) => `[`SystemReportFormat`](https://www.adaptabletools.com/docs/reference/systemreportformat.md)`[])` | System Report Formats to use; leave unset for all, empty array for none | 'Excel', 'VisualExcel', 'CSV', 'JSON' | | [systemReportNames](https://www.adaptabletools.com/docs/reference/exportoptions.md#systemreportnames) | [`SystemReportName`](https://www.adaptabletools.com/docs/reference/systemreportname.md)`[] \| ((context: `[`SystemReportNamesContext`](https://www.adaptabletools.com/docs/reference/systemreportnamescontext.md)`) => `[`SystemReportName`](https://www.adaptabletools.com/docs/reference/systemreportname.md)`[])` | System Reports to use; leave unset for all, empty array for none | 'All Data', 'Current Layout', 'Selected Data', | ------- ## Export API The [`Export API`](https://www.adaptabletools.com/docs/reference/exportapi.md) section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) contains a number of functions enabling Reports to be run - and managed more generally - at run-time: | Method | Returns | Description | | --- | --- | --- | | [addScheduledReport(reportSchedule)](https://www.adaptabletools.com/docs/reference/exportapi.md#addscheduledreport) | `void` | Adds a scheduled report | | [applyScheduledReport(reportSchedule)](https://www.adaptabletools.com/docs/reference/exportapi.md#applyscheduledreport) | `void` | Runs a scheduled export and records the job-run action | | [canExportToCsv()](https://www.adaptabletools.com/docs/reference/exportapi.md#canexporttocsv) | `boolean` | If this AdapTable instance can to export to CSV; if false, the Export to Csv option will not be visible | | [canExportToExcel()](https://www.adaptabletools.com/docs/reference/exportapi.md#canexporttoexcel) | `boolean` | If this AdapTable instance can to export to Excel; if false, the Export to Excel option will not be visible | | [clearFormat()](https://www.adaptabletools.com/docs/reference/exportapi.md#clearformat) | `void` | Sets the Report Format to null | | [clearReport()](https://www.adaptabletools.com/docs/reference/exportapi.md#clearreport) | `void` | Sets the Report to null | | [deleteScheduledReport(reportSchedule)](https://www.adaptabletools.com/docs/reference/exportapi.md#deletescheduledreport) | `void` | Deletes a scheduled report | | [editScheduledReport(reportSchedule)](https://www.adaptabletools.com/docs/reference/exportapi.md#editscheduledreport) | `void` | Edits a scheduled report | | [ensureScheduledReportUuids()](https://www.adaptabletools.com/docs/reference/exportapi.md#ensurescheduledreportuuids) | `void` | Ensures every scheduled report has a unique Uuid (legacy state may omit them). | | [exportReport(reportName, format, destination, exportConfig)](https://www.adaptabletools.com/docs/reference/exportapi.md#exportreport) | `Promise` | Exports the Report with the given Name and Format to the given Destination | | [getActiveScheduledReports(config)](https://www.adaptabletools.com/docs/reference/exportapi.md#getactivescheduledreports) | [`ReportSchedule`](https://www.adaptabletools.com/docs/reference/reportschedule.md)`[]` | All active scheduled reports (custom reports and system reports) | | [getAllExportDestinations()](https://www.adaptabletools.com/docs/reference/exportapi.md#getallexportdestinations) | [`ExportDestinationType`](https://www.adaptabletools.com/docs/reference/exportdestinationtype.md)`[]` | Retrieves the available export destinations | | [getAllFormats()](https://www.adaptabletools.com/docs/reference/exportapi.md#getallformats) | [`ReportFormatType`](https://www.adaptabletools.com/docs/reference/reportformattype.md)`[]` | Retrieves all Report Formats that are available | | [getAllReports()](https://www.adaptabletools.com/docs/reference/exportapi.md#getallreports) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md)`[]` | Retrieves all available Reports - System and User-created Reports | | [getAvailableCustomDestinations()](https://www.adaptabletools.com/docs/reference/exportapi.md#getavailablecustomdestinations) | [`CustomDestination`](https://www.adaptabletools.com/docs/reference/customdestination.md)`[]` | Retrieves available Custom Destinations (configured in Export Options) | | [getAvailableSystemDestinations()](https://www.adaptabletools.com/docs/reference/exportapi.md#getavailablesystemdestinations) | [`SystemExportDestination`](https://www.adaptabletools.com/docs/reference/systemexportdestination.md)`[]` | Retrieves available System Export Destinations (configured in Export Options) | | [getAvailableSystemFormats()](https://www.adaptabletools.com/docs/reference/exportapi.md#getavailablesystemformats) | [`SystemReportFormat`](https://www.adaptabletools.com/docs/reference/systemreportformat.md)`[]` | Retrieves available System Report Formats (configured in Export Options) | | [getAvailableSystemReports()](https://www.adaptabletools.com/docs/reference/exportapi.md#getavailablesystemreports) | [`SystemReportName`](https://www.adaptabletools.com/docs/reference/systemreportname.md)`[]` | Retrieves available System Reports (configured in Export Options) | | [getCurrentReport()](https://www.adaptabletools.com/docs/reference/exportapi.md#getcurrentreport) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md)` \| undefined` | Retrieves currently selected Report in Adaptable State | | [getCurrentReportFormat()](https://www.adaptabletools.com/docs/reference/exportapi.md#getcurrentreportformat) | [`ReportFormatType`](https://www.adaptabletools.com/docs/reference/reportformattype.md)` \| undefined` | Retrieves name of currently selected Report | | [getCurrentReportName()](https://www.adaptabletools.com/docs/reference/exportapi.md#getcurrentreportname) | [`ReportNameType`](https://www.adaptabletools.com/docs/reference/reportnametype.md)` \| undefined` | Retrieves name of currently selected Report | | [getCustomReports()](https://www.adaptabletools.com/docs/reference/exportapi.md#getcustomreports) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md)`[]` | Retrieves all Custom Reports that have been created by the User | | [getDestinationByName(destinationName)](https://www.adaptabletools.com/docs/reference/exportapi.md#getdestinationbyname) | [`SystemExportDestination`](https://www.adaptabletools.com/docs/reference/systemexportdestination.md)` \| `[`CustomDestination`](https://www.adaptabletools.com/docs/reference/customdestination.md)` \| undefined` | Retrieves Destination with the given name | | [getExportDestinationForm(destinationName)](https://www.adaptabletools.com/docs/reference/exportapi.md#getexportdestinationform) | [`AdaptableForm`](https://www.adaptabletools.com/docs/reference/adaptableform.md)`<`[`ExportFormContext`](https://www.adaptabletools.com/docs/reference/exportformcontext.md)`> \| undefined` | Form Data entered by the User in the UI for a Custom Destination | | [getExportState()](https://www.adaptabletools.com/docs/reference/exportapi.md#getexportstate) | [`ExportState`](https://www.adaptabletools.com/docs/reference/exportstate.md) | Retrieves Export section from Adaptable State | | [getReportById(id)](https://www.adaptabletools.com/docs/reference/exportapi.md#getreportbyid) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md) | Retrieves Report by Id | | [getReportByName(reportName)](https://www.adaptabletools.com/docs/reference/exportapi.md#getreportbyname) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md)` \| undefined` | Retrieves Report with the given name | | [getReportData(reportName, format, config)](https://www.adaptabletools.com/docs/reference/exportapi.md#getreportdata) | `Promise<`[`ExportResultData`](https://www.adaptabletools.com/docs/reference/exportresultdata.md)`>` | Gets the data for the Report with the given Name in the given Format | | [getScheduledReportById(reportScheduleId, config)](https://www.adaptabletools.com/docs/reference/exportapi.md#getscheduledreportbyid) | [`ReportSchedule`](https://www.adaptabletools.com/docs/reference/reportschedule.md)` \| undefined` | Retrieves a scheduled report by its Uuid | | [getScheduledReports(config)](https://www.adaptabletools.com/docs/reference/exportapi.md#getscheduledreports) | [`ReportSchedule`](https://www.adaptabletools.com/docs/reference/reportschedule.md)`[]` | All scheduled reports (custom reports and system reports) | | [getSupportedExportDestinations(reportFormat)](https://www.adaptabletools.com/docs/reference/exportapi.md#getsupportedexportdestinations) | [`ExportDestinationType`](https://www.adaptabletools.com/docs/reference/exportdestinationtype.md)`[]` | Retrieves the Export Destinations that are supported for the given Report Format | | [isColumnExportable(adaptablColumn)](https://www.adaptabletools.com/docs/reference/exportapi.md#iscolumnexportable) | `boolean` | Returns whether the given column is exportable | | [isExportDestinationSystem(destinationName)](https://www.adaptabletools.com/docs/reference/exportapi.md#isexportdestinationsystem) | `boolean` | If the given destination is a System one | | [openExportSettingsPanel()](https://www.adaptabletools.com/docs/reference/exportapi.md#openexportsettingspanel) | `void` | Open Settings Panel with Export section selected | | [selectFormat(reportFormat)](https://www.adaptabletools.com/docs/reference/exportapi.md#selectformat) | `void` | Selects the Report Format for Export | | [selectReport(reportName)](https://www.adaptabletools.com/docs/reference/exportapi.md#selectreport) | `void` | Selects the Report in the Adaptable State | | [suspendScheduledReport(reportSchedule)](https://www.adaptabletools.com/docs/reference/exportapi.md#suspendscheduledreport) | `void` | Suspends a scheduled report | | [unSuspendScheduledReport(reportSchedule)](https://www.adaptabletools.com/docs/reference/exportapi.md#unsuspendscheduledreport) | `void` | Unsuspends a scheduled report | | [updateReport(report)](https://www.adaptabletools.com/docs/reference/exportapi.md#updatereport) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md) | Updates an existing report | | [updateReports(reports)](https://www.adaptabletools.com/docs/reference/exportapi.md#updatereports) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md)`[]` | Updates existing reports | ------- ## Report Schedule Ran Event The Report Schedule Ran Event is published whenever any report runs on a Schedule. The [`ReportScheduleRanInfo`](https://www.adaptabletools.com/docs/reference/reportscheduleraninfo.md) provides full information on the Report and the Schedule: | Property | Type | Description | | --- | --- | --- | | [RanAt](https://www.adaptabletools.com/docs/reference/reportscheduleraninfo.md#ranat) | `string` | ISO datetime when Schedule ran (useful for logging) | | [reportSchedule](https://www.adaptabletools.com/docs/reference/reportscheduleraninfo.md#reportschedule) | [`ReportSchedule`](https://www.adaptabletools.com/docs/reference/reportschedule.md) | Report schedule that was triggered (if applicable) | | [adaptableContext](https://www.adaptabletools.com/docs/reference/reportscheduleraninfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ------- ## Live Data Changed Event The Live Data Changed Event is published whenever any report which contains Live Data (i.e. if using [ipushpull](https://www.adaptabletools.com/docs/integrations-ipushpull/index.md) or [OpenFin](https://www.adaptabletools.com/docs/integrations-openfin/index.md) plugins) is changed. ### Live Report The [`Live Report`](https://www.adaptabletools.com/docs/reference/livereport.md) defines which Adaptable Reports are 'Live' (i.e. they will update the destination as the data in Adaptable ticks or changes): When Adaptable creates a Live Report it will take care of updating the destination as the data in the Report changes (based on the throttle time it is given). | Property | Type | Description | | --- | --- | --- | | [pageName](https://www.adaptabletools.com/docs/reference/livereport.md#pagename) | `string` | For OpenFin this is the workbook name; for iPushpull the page name | | [report](https://www.adaptabletools.com/docs/reference/livereport.md#report) | [`Report`](https://www.adaptabletools.com/docs/reference/report.md) | The underlying Report | | [reportDestination](https://www.adaptabletools.com/docs/reference/livereport.md#reportdestination) | `'OpenfinExcel' \| 'ipushpull'` | Where the live data is being sent | --- # FDC3 in AdapTable Canonical page: https://www.adaptabletools.com/docs/handbook-fdc3 - AdapTable provides powerful FDC3 functionality - with full support for FDC3 2.1 - All FDC3 Intents and Contexts can be raised, broadcast and listened to as required - Custom FDC3 is also fully supported ## Understanding FDC3 AdapTable provides full and comprehensive support for [FDC3](https://fdc3.finos.org/) - the Open Standard for the financial desktop. The mission of the Financial Desktop Connectivity and Collaboration Consortium (FDC3) is to develop specific protocols and taxonomies to advance the ability of desktop applications in financial workflows to interoperate in a plug-and-play fashion, without prior bi-lateral agreements. FDC3 provides an open standard for interoperability between applications on the financial desktop. End-users of AdapTable are able to access FDC3 in a number of ways including: - **raise**, and listen for, FDC3 **Intents** - **broadcast**, and listen for, FDC3 **Contexts** - use **Custom** Intents and Contexts In [Version 19](https://www.adaptabletools.com/support/version-190-release-note), AdapTable provided full support for [FDC3 2.1](https://fdc3.finos.org/docs/fdc3-intro) - a major re-write of the FDC3 standard ## How it Works FDC3 support in AdapTable is provided at design-time by developers using FDC3 Options. AdapTable's FDC3 configuration is managed via a 2 step-process: 1. provide [FDC3 Data Mappings](https://www.adaptabletools.com/docs/handbook-fdc3-mappings/index.md) - essentially mapping formal FDC3 types against AdapTable Columns 2. use these mappings to raise and listen for [Intents](#intents), and broadcast and listen for [Contexts](#contexts) - Most AdapTable users who access FDC3, also use a FDC3-supporting platform like [OpenFin](https://www.adaptabletools.com/docs/integrations-openfin/index.md), [interop.io](https://www.adaptabletools.com/docs/integrations-interop/index.md) or [Connectifi](https://www.connectifi.co/) - AdapTable provides a plugin for each container which automatically connects to the FDC3 implementation - For instance, AdapTable will wire up its FDC3 Broadcasts and Intents and publish them on a shared channel - It is possible to use FDC3 in AdapTable *natively* without using the containers listed above - FDC3 provides a powerful way of communicating between multiple AdapTable instances ### Grid Data Mappings AdapTable's FDC3 support is **data-centric**. Grid Data Mappings provide the "glue" to map the Grid's data and columns to FDC3 behaviour. Essentially they tell AdapTable which columns in the Grid to use when creating Intents and Contexts. Mappings are provided in the `gridDataContextMapping` property of FDC3 Options. ֵEach entry has a key of a formal FDC3 type and an associated mapping to existing Grid Columns. See [FDC3 Grid Data Mappings](https://www.adaptabletools.com/docs/handbook-fdc3-mappings/index.md) for full details ### Intents Intents are FDC3 **actions** that a user wants to perform or react to. According to the official [FDC3 Documentation](https://fdc3.finos.org/docs/intents/spec): FDC3 Intents define a standard set of verbs that, in conjunction with context data acting as nouns, can be used to put together common cross-application workflows on the financial desktop. AdapTable supports Intents through the `intents` property in FDC3 Options. This contains 2 properties: - `raises` - provides a list of FDC3 Intents which can be raised Intents can be raised either via a [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) item or by creating an [Action Column Button](https://www.adaptabletools.com/docs/handbook-action-column/index.md) - `listensFor` - lists the FDC3 Intents to which the Grid will listen Intents are listened to by implementing the `handleIntent` property function - also in FDC3 Options See [FDC3 Intents](https://www.adaptabletools.com/docs/handbook-fdc3-intents/index.md) for the full, official specification ### Contexts If [Intents](#intents) are the verbs that define actions, then Contexts are the accompanying nouns. According to the official [FDC3 Documentation](https://fdc3.finos.org/docs/context/spec): FDC3 Context Data defines a standard for passing common identifiers and data between apps to create a seamless workflow....Context objects are used when raising intents and when broadcasting context to other applications. AdapTable supports FDC3 Contexts through the `contexts` property in FDC3 Options. This contains 2 properties: - `broadcasts` - publishes information about a given FDC3 Context Context can be broadcast either via a [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) item or by creating an [Action Column Button](https://www.adaptabletools.com/docs/handbook-action-column/index.md) - `listensFor` - lists the FDC3 Contexts to which the Grid will listen Context is listened to by implementing the `handleContext` property function - also in FDC3 Options See [FDC3 Contexts](https://www.adaptabletools.com/docs/handbook-fdc3-context/index.md) for the full, official specification ### Custom FDC3 Typically users will want to raise intents and broadcast contexts which are officially provided by FDC3. However AdapTable also supports Custom FDC3 context and intents. This can be used to communicate between multiple AdapTable instances or between AdapTable and other applications in your workflow. See [Providing Custom FDC3](https://www.adaptabletools.com/docs/handbook-fdc3-custom/index.md) for full details ## FDC3 UI Components Developers are easily able to configure the AdapTable UI to perform FDC3-related actions. ### FDC3 Action Columns This is primarily achieved through **FDC3 Action Columns**. These are normal [Action Columns](https://www.adaptabletools.com/docs/handbook-action-column/index.md) (used widely in AdapTable) which are leveraged for FDC3 purposes. These dynamically created Columns will display buttons used for Raising Intents or Broadcasting Contexts. FDC3 Action Columns can be provided in 2 ways: - By providing **Action Buttons** - which AdapTable will then display in the default FDC3 Action Column - By providing a custom FDC3 **Action Column** - which AdapTable will render as required Both types of Column need to be directly referenced in any Layouts you provide The Buttons and Action Columns are defined inside whichever Intents and / or Contexts they reference. ### FDC3 Context Menu Items Another way to use the AdapTable UI to perform FDC3 activity is through [Context Menu Items](https://www.adaptabletools.com/docs/ui-context-menu/index.md). These can used to raise Intents or to broadcast Context. Developers provided the menu configuration details in FDC3 Options, and AdapTable will wire up the menu items automatically. See [FDC3 UI Components](https://www.adaptabletools.com/docs/handbook-fdc3-ui-components/index.md) for full details ## FDC3 Message Event AdapTable fires the [FDC3 Message Event](https://www.adaptabletools.com/docs/handbook-fdc3-technical-reference/index.md) whenever an FDC3 Message is sent or received. ## UI Entitlements The [UI Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) behaviour for FDC3 is that `ReadOnly` and `Full` Access Levels are identical (since everything is provided at design-time). --- # FDC3 Context Canonical page: https://www.adaptabletools.com/docs/handbook-fdc3-context - This AdapTable Help Page is being actively updated - AdapTable has just upgraded to FDC3 2.0 and we are working on updating the documentation - AdapTable fully supports FDC3 Contexts; users can: - Broadcast Context - Listen for Context - Create Custom Context AdapTable supports FDC3 Contexts through the `contexts` property in FDC3 Options. This object is of type [`Fdc3ContextOptions`](https://www.adaptabletools.com/docs/reference/fdc3contextoptions.md) and contains these properties: | Property | Type | Description | | --- | --- | --- | | [broadcasts](https://www.adaptabletools.com/docs/reference/fdc3contextoptions.md#broadcasts) | [`BroadcastConfiguration`](https://www.adaptabletools.com/docs/reference/broadcastconfiguration.md) | Broadcasts given standard Context(s) on various Grid Actions | | [handleContext](https://www.adaptabletools.com/docs/reference/fdc3contextoptions.md#handlecontext) | `(context: `[`HandleFdc3Context`](https://www.adaptabletools.com/docs/reference/handlefdc3context.md)`) => void` | Handles incoming Contexts (standard and custom) | | [listensFor](https://www.adaptabletools.com/docs/reference/fdc3contextoptions.md#listensfor) | `ContextType[]` | Subscribe to given standard Context(s) | As can be seen, users are able both to **Broadcast** and **Listen For** FDC3 Context. ## Available Contexts The FDC3 Intents supported by AdapTable (and the Intents they can raise) are as follows: | FDC3 Context | Available Intents | | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [Chart](https://fdc3.finos.org/docs/context/ref/Chart) | [ViewChart](https://fdc3.finos.org/docs/intents/ref/ViewChart) | | [ChatInitSettings](https://fdc3.finos.org/docs/context/ref/ChatInitSettings) | [StartChat](https://fdc3.finos.org/docs/intents/ref/StartChat) , [StartCall](https://fdc3.finos.org/docs/intents/ref/StartCall), [ViewContact](https://fdc3.finos.org/docs/intents/ref/ViewContact) | | [Contact](https://fdc3.finos.org/docs/context/ref/Contact) | [StartChat](https://fdc3.finos.org/docs/intents/ref/StartChat) , [StartCall](https://fdc3.finos.org/docs/intents/ref/StartCall) | | [ContactList](https://fdc3.finos.org/docs/context/ref/ContactList) | [StartChat](https://fdc3.finos.org/docs/intents/ref/StartChat) , [StartCall](https://fdc3.finos.org/docs/intents/ref/StartCall), [ViewProfile](https://fdc3.finos.org/docs/intents/ref/ViewProfile), [ViewResearch](https://fdc3.finos.org/docs/intents/ref/ViewResearch), [ViewInteractions](https://fdc3.finos.org/docs/intents/ref/ViewInteractions), [ViewOrders](https://fdc3.finos.org/docs/intents/ref/ViewOrders) | | [Country](https://fdc3.finos.org/docs/context/ref/Country) | [ViewAnalysis](https://fdc3.finos.org/docs/intents/ref/ViewAnalysis), [ViewNews](https://fdc3.finos.org/docs/intents/ref/ViewNews) | | [Currency](https://fdc3.finos.org/docs/context/ref/Currency) | | | [Email](https://fdc3.finos.org/docs/context/ref/Chart) | [StartEmail](https://fdc3.finos.org/docs/intents/ref/StartEmail) | | [Instrument](https://fdc3.finos.org/docs/context/ref/Instrument) | [ViewAnalysis](https://fdc3.finos.org/docs/intents/ref/ViewAnalysis), [ViewChart](https://fdc3.finos.org/docs/intents/ref/ViewChart), [ViewInstrument](https://fdc3.finos.org/docs/intents/ref/ViewInstrument), [ViewNews](https://fdc3.finos.org/docs/intents/ref/ViewNews), [ViewQuote](https://fdc3.finos.org/docs/intents/ref/ViewQuote), [ViewResearch](https://fdc3.finos.org/docs/intents/ref/ViewResearch), [ViewInteractions](https://fdc3.finos.org/docs/intents/ref/ViewInteractions), [ViewOrders](https://fdc3.finos.org/docs/intents/ref/ViewOrders) | | [InstrumentList](https://fdc3.finos.org/docs/context/ref/InstrumentList) | [ViewAnalysis](https://fdc3.finos.org/docs/intents/ref/ViewAnalysis), [ViewChart](https://fdc3.finos.org/docs/intents/ref/ViewChart), [ViewInstrument](https://fdc3.finos.org/docs/intents/ref/ViewInstrument), [ViewNews](https://fdc3.finos.org/docs/intents/ref/ViewNews), [ViewQuote](https://fdc3.finos.org/docs/intents/ref/ViewQuote) | | [Organization](https://fdc3.finos.org/docs/context/ref/Organization) | [ViewAnalysis](https://fdc3.finos.org/docs/intents/ref/ViewAnalysis), [ViewNews](https://fdc3.finos.org/docs/intents/ref/ViewNews), [ViewProfile](https://fdc3.finos.org/docs/intents/ref/ViewProfile), [ViewResearch](https://fdc3.finos.org/docs/intents/ref/ViewResearch), [ViewInteractions](https://fdc3.finos.org/docs/intents/ref/ViewInteractions), [ViewOrders](https://fdc3.finos.org/docs/intents/ref/ViewOrders) | | [Portfolio](https://fdc3.finos.org/docs/context/ref/Portfolio) | [ViewAnalysis](https://fdc3.finos.org/docs/intents/ref/ViewAnalysis), [ViewChart](https://fdc3.finos.org/docs/intents/ref/ViewChart), [ViewNews](https://fdc3.finos.org/docs/intents/ref/ViewNews) | | [Position](https://fdc3.finos.org/docs/context/ref/Position) | [ViewAnalysis](https://fdc3.finos.org/docs/intents/ref/ViewAnalysis), [ViewChart](https://fdc3.finos.org/docs/intents/ref/ViewChart), [ViewNews](https://fdc3.finos.org/docs/intents/ref/ViewNews) | | [TimeRange](https://fdc3.finos.org/docs/context/ref/TimeRange) | | | [Valuation](https://fdc3.finos.org/docs/context/ref/Valuation) | | ## Broadcasting Context FDC3 Contexts are broadcast using the `broadcasts` property in the `contexts` section of FDC3 Options. Each Context is listed by type (e.g. `fdc3.instrument`) and details the context-broadcasting behaviour. - Make sure **all contexts** you broadcast are referenced in the `gridDataContextMapping` property of FDC3 Options - This is a required step which AdapTable uses to [map columns and fields to FDC3 objects](https://www.adaptabletools.com/docs/u/handbook-fdc3-mappings) This context-broadcasting behaviour can take one of 2 forms: - a [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) entry - an [FDC3 Action Column](https://www.adaptabletools.com/docs/u/handbook-fdc3-ui-components) (either a button or full Column definition can be provided) It is possible to broadcast Context using the **both** [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) and an [FDC3 Action Column](https://www.adaptabletools.com/docs/u/handbook-fdc3-ui-components) ### `broadcasts` Broadcasts given standard Context(s) on various Grid Actions [`BroadcastConfiguration`](https://www.adaptabletools.com/docs/reference/broadcastconfiguration.md) Property which defines which FDC3 Contexts can be broadcast. It provides an object of type [`BroadcastConfiguration`](https://www.adaptabletools.com/docs/reference/broadcastconfiguration.md) which contains a collection of [`BroadcastConfig`](https://www.adaptabletools.com/docs/reference/broadcastconfig.md) objects. Each has Config object has 2 elements: - a **key** which is the Context being broadcast (e.g. `fdc3.instrument`, `fdc3.currency`). - This context should be referenced in the `gridDataContextMapping` property of FDC3 Options - See [Mapping columns and fields to FDC3 objects](https://www.adaptabletools.com/docs/u/handbook-fdc3-mappings) for more information - properties to define the Broadcast **behaviour**, i.e. via the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) or using an [Action Column / Button](https://www.adaptabletools.com/docs/handbook-action-column/index.md): See [FDC3 Action Columns and Buttons](https://www.adaptabletools.com/docs/handbook-fdc3-ui-components/index.md) for full details on how these Buttons and Action Columns are rendered | Property | Type | Description | | --- | --- | --- | | [actionButton](https://www.adaptabletools.com/docs/reference/broadcastconfig.md#actionbutton) | [`Fdc3AdaptableButton`](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md) | Definition of Action Button (to be put in default FDC3 Action Column) | | [actionColumn](https://www.adaptabletools.com/docs/reference/broadcastconfig.md#actioncolumn) | [`FDC3ActionColumn`](https://www.adaptabletools.com/docs/reference/fdc3actioncolumn.md) | Custom FDC3 Action Column definition to broadcast the Context | | [contextMenu](https://www.adaptabletools.com/docs/reference/broadcastconfig.md#contextmenu) | `\{ columnIds: string[]; icon?: '_defaultFdc3' \| `[`AdaptableIcon`](https://www.adaptabletools.com/docs/reference/adaptableicon.md)`; \}` | Columns to display a 'Broadcast' Context Menu item | ```tsx {2} contexts: { broadcasts: { 'fdc3.currency': { contextMenu: { columnIds: ['currency'], icon: '_defaultFdc3', }, actionButton: { id: 'BroadCastCurrencyButton', icon: '_defaultFdc3', tooltip: '_defaultFdc3', }, }, 'fdc3.email': { contextMenu: { columnIds: ['interest'], icon: '_defaultFdc3', }, }, }, }, ``` ## Listening for Context Listening for Context (that has been broadcast from external applications) is done in 2 stages: Both steps use a property in the `contexts` section of FDC3 Options - all Contexts to handle are listed in the `listensFor` property - an implementation is given for the `handleContext` function property ### `listensFor` Subscribe to given standard Context(s) [`Fdc3ContextType`](https://www.adaptabletools.com/docs/reference/fdc3contexttype) Lists which FDC3 Contexts are listened for. The array is of type [`Fdc3ContextType`](https://www.adaptabletools.com/docs/reference/fdc3contexttype) which are FDC3 strings (e.g. `fdc3.instrument`, `fdc3.contact`) ```tsx {2} contexts: { listensFor: ['fdc3.instrument', 'fdc3.contact'], }, ``` These Contexts are then typically handled in the `handleContext` function property (see below). ## Handling Context Incoming FDC3 Context is handled by the `handleContext` property. ### `handleContext` Handles incoming Contexts (standard and custom) Property used to handle incoming FDC3 Context. Make sure that the Context is listed in the `listensFor` property - also in the `contexts` object ```tsx handleContext?: (context: HandleFdc3Context) => void; ``` The void function receives an object of type [`HandleFdc3Context`](https://www.adaptabletools.com/docs/reference/handlefdc3context.md) which contains two FDC3 2.0 objects: | Property | Type | Description | | --- | --- | --- | | [context](https://www.adaptabletools.com/docs/reference/handlefdc3context.md#context) | `Context` | The FDC3 Context | | [metadata](https://www.adaptabletools.com/docs/reference/handlefdc3context.md#metadata) | `ContextMetadata` | The FDC3 Context Metadata related to the context | | [adaptableContext](https://www.adaptabletools.com/docs/reference/handlefdc3context.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```tsx {2} contexts: { handleContext: (fdc3Context: HandleFdc3Context) => { console.log(`Received context: `, fdc3Context); }, }, ``` --- # Custom FDC3 Contexts & Intents Canonical page: https://www.adaptabletools.com/docs/handbook-fdc3-custom - This AdapTable Help Page is coming soon... - AdapTable has just upgraded to FDC3 2.0 and we will update the documentation asap --- # FDC3 Demo App Canonical page: https://www.adaptabletools.com/docs/handbook-fdc3-example - This page describes a demo app that illustrates AdapTable's FDC3 capability - The app leverages the first-rate [Connectifi Sandbox](https://apps.connectifi-interop.com/sandbox) which can be used for testing FDC3 FDC3 is all about interopability with **external** applications and widgets. For this reason, its not possible to provide an isolated demo of FDC3 features in AdapTable, in the same way we can for all other AdapTable Modules. Instead this page walks through an existing FDC3 Demo that illustrates some of AdapTable's FDC3 functionality. - To run the demo click this [link](https://apps.connectifi-interop.com/sandbox) and then select AdapTable - The demo code is available [here](https://github.com/AdaptableTools/connectifi-fdc3-demo) with this [ReadMe](https://github.com/AdaptableTools/connectifi-fdc3-demo/blob/master/README.md) ## Demo Introduction In the demo app we illustrate how AdapTable users are able to: - Raise FDC3 Intents - Listen for FDC3 Intents - Broadcast FDC3 Context - Listen for FDC3 Context - Raise a Custom FDC3 Intent - Define FDC3 Action Buttons, Action Columns and Context Menu Items - The demo app primarily uses the [FDC3 Instrument Context](https://fdc3.finos.org/docs/context/ref/Instrument) to manage Intents and Context - But all FDC3 context types are available out of the box in AdapTable The demo leverages the excellent - and free(!) - [Connectifi Sandbox](https://apps.connectifi-interop.com/sandbox) as the desktop agent The data in the app is purely meaningless **dummy data** for illustration purposes; only the Tickers are real ## Demo Step by Step Here are the key steps performed by the demo to leverage AdapTable's FDC3 functionality: ### Creating the demo FDC3 app Create [FDC3 Data Mapping](https://www.adaptabletools.com/docs/handbook-fdc3-mappings/index.md) - to [FDC3 Instrument Context](https://fdc3.finos.org/docs/context/ref/Instrument): - Use `Name` column (defined by '\_colId') as the Instrument Nam3 - Use `Symbol` field (defined by '\_field') to map to Ticker (in `id` prop) ```tsx {2} fdc3Options: { gridDataContextMapping: { 'fdc3.instrument': { name: '_colId.Name', id: { ticker: '_field.Symbol' }, }, }, } ``` - Mappings provide the “glue” to map AG Grid’s data and columns to required FDC3 behaviour - AdapTable looks at the mappings to work out which columns to use when creating Intents and Contexts - This app has just one mapping but there is no limit to how many can be provided The demo app raises 3 FDC3 Intents - defined in the `raises` property in the `intents` section: - `ViewChart` - `ViewNews` - `ViewInstrument` It provides an Action Button definition for each Intent to be raised. These will then be rendered in the default FDC3 Action Column. The key for each item is the name of the Intent being raised. The app also raises a Custom Intent which is discussed below ```ts {1,2,13,24} raises: { ViewChart: [ { contextType: 'fdc3.instrument', actionButton: { id: 'viewChartBtn', tooltip: 'Raise: ViewChart', icon: '_defaultFdc3', buttonStyle: { tone: 'info', variant: 'outlined' }, }, }, ], ViewNews: [ { contextType: 'fdc3.instrument', actionButton: { id: 'viewNewsBtn', tooltip: 'Raise: ViewNews', icon: '_defaultFdc3', buttonStyle: { variant: 'outlined', tone: 'warning' }, }, }, ], ViewInstrument: [ { contextType: 'fdc3.instrument', actionButton: { id: 'viewInstrumentBtn', tooltip: 'Raise: ViewInstrument', icon: { name: 'visibility-on' }, buttonStyle: { tone: 'error', variant: 'outlined' }, }, }, ], }, ``` Intents are listened for using the `listensFor` property (in the `intents` section) The demo app listens for the `ViewInstrument` Intent and provides an accompanying implementation of the `handleIntent` property which: - jumps to, and highlights in yellow for 5 seconds, the row which contains the instrument (using [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md)) - sends a [System Status Message](https://www.adaptabletools.com/docs/handbook-system-status-message/index.md) displaying the Context received ```ts {1,3} listensFor: ['ViewInstrument'], handleIntent: (handleFDC3Context: HandleFdc3Context) => { const adaptableApi: AdaptableApi = handleFDC3Context.adaptableApi; const ticker = handleFDC3Context.context.id?.ticker; // Create Row Highlight object, then jump to Row and higlight it const rowHighlightInfo: RowHighlightInfo = { primaryKeyValue: ticker, timeout: 5000, highlightStyle: { BackColor: 'Yellow', ForeColor: 'Black' }, }; adaptableApi.gridApi.jumpToRow(ticker); adaptableApi.gridApi.highlightRow(rowHighlightInfo); // Display Info System Status Message with details of Intent received adaptableApi.systemStatusApi.setInfoSystemStatus( 'Intent Received: ' + ticker, JSON.stringify(handleFDC3Context.context), ); }, ``` The FDC3 Context is broadcast using the `broadcasts` property: The demo app Broadcasts FDC3 Instrument Context in 2 ways: - using Context Menu Items in the `Name` and `Ticker` columns - via an FDC3 Action Button - which will be rendered in the default FDC3 Action Column The key for each item is the Context mapping created in FDC3 Grid Data Mappings (in Stage 1) ```ts {1,2} broadcasts: { 'fdc3.instrument': { contextMenu: { columnIds: ['Ticker', 'Name'], icon: '_defaultFdc3', }, actionButton: { id: 'broadcastInstrumentBtn', icon: { name: 'broadcast' }, tooltip: `Broadcast: Instrument`, buttonStyle: { tone: 'success', variant: 'outlined' }, }, }, }, ``` The demo app listens for the `fdc3.instrument` Context, using the `listensFor` property. As is typically the case, this property is accompanied by an implementation of the `handleContext` property which performs any necesary accompanying behaviour. In the demo app, the function is used to: - [Filter](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) the Grid using the Ticker received in the Context - send a [System Status Message](https://www.adaptabletools.com/docs/handbook-system-status-message/index.md) displaying the Context received ```ts {1,3} listensFor: ['fdc3.instrument'], handleContext: (handleFDC3Context: HandleFdc3Context) => { if (handleFDC3Context.context.type === 'fdc3.instrument') { const adaptableApi: AdaptableApi = handleFDC3Context.adaptableApi; const ticker = handleFDC3Context.context.id?.ticker; // Filter the Grid using the received Ticker adaptableApi.filterApi.columnFilterApi.setColumnFilterForColumn('Ticker', { PredicateId: 'Is', PredicateInputs: [handleFDC3Context.context.id?.ticker], }); // Display Success System Status Message with details of Context received adaptableApi.systemStatusApi.setSuccessSystemStatus( 'Context Received: ' + ticker, JSON.stringify(handleFDC3Context.context), ); } }, ``` AdapTable fully supports Custom FDC3. In this app we raise a Custom `GetPrice` intent. This integrates with functionality provided by the [Connectifi Sandbox](https://apps.connectifi-interop.com/sandbox) to illustrate usage of custom FDC3 The demo app uses Custom FDC3 context as follow: - defines the Custom Intent to raise in the `custom` property in the `intents` section - provides the name of the Custom Intent to raise as the key (here `GetPrice`) - supplies a context type of `fdc3.instrument`, which matches the Grid Data Mappings previously defined - defines a bespoke Action Column definition (which AdapTable will render as a separate column) - provides an implementation for the `handleIntentResolution` property (which is typically provided when raising Custom Intents) - the function replaces the Action Column button with the result (here a Price) returned from the Intent ```ts {1,2,32} custom: { GetPrice: [ { contextType: 'fdc3.instrument', actionColumn: { columnId: 'fdc3GetPriceColumn', friendlyName: 'Get Price', button: { id: 'GetPriceButton', label: (button, context) => { const price = priceMap.get(context.rowData.Symbol); return !!price ? `$ ${price}` : 'Get Price'; }, icon: (button, context) => { const price = priceMap.get(context.rowData.Symbol); return !price ? { name: 'quote' } : null; }, tooltip: (button, context) => { return `Get Price Info for ${context.rowData.Symbol}`; }, buttonStyle: (button, context) => { return priceMap.has(context.rowData.Symbol) ? { tone: 'success', variant: 'text', } : { tone: 'info', variant: 'outlined', }; }, disabled: (button, context) => { return priceMap.has(context.rowData.Symbol); }, }, }, // Handle intent resolution by showing returned Price in Column handleIntentResolution: async ( context: HandleFdc3IntentResolutionContext, ) => { const result = await context.intentResolution.getResult(); if (!result?.type) { return; } const api: AdaptableApi = context.adaptableApi; const contextData = intentResult as Fdc3CustomContext; const ticker = contextData.id?.ticker; const price = contextData.price; if (ticker) { priceMap.set(ticker, price) } api.gridApi.refreshColumn('fdc3GetPriceColumn'); }, }, ], }, ``` The demo uses all 3 FDC3 UI components that AdapTable provides: - Intents are raised using FDC3 Action Buttons - The Custom Intent is displayed in a bespoke [FDC3 Action Column](https://www.adaptabletools.com/docs/handbook-fdc3-ui-components/index.md) - Context is broadcast using FDC3 [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) Items The demo app overrides the default FDC3 Action column properties set by AdapTable to make the column narrower than the default. ```ts {2} // Narrow width of Default Action Column actionColumnDefaultConfiguration: { width: 150, }, ``` Both the **default** FDC3 Action Column and **bespoke** FDC3 Action Columns must be referenced in a Layout. Hence the demo app lists them in the `TableColumns` property in the [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md). ```ts {9,11} Layout: { CurrentLayout: 'Table Layout', Layouts: [ Name: 'Table Layout', TableColumns: [ 'Ticker', 'Name', 'Price', 'fdc3GetPriceColumn', // Bespoke FDC3 Action Column 'Position', 'fdc3ActionColumn', // Default FDC3 Action Column 'Sector', 'SectorPnl', ], }, ], }, ``` ## Other AdapTable Objects The demo app contains a few other AdapTable [Initial Adaptable State sections](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md) and [Adaptable Options properties](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) to create a more pleasing and realistic visual effect. These include: - [Theme](https://www.adaptabletools.com/docs/handbook-theming/index.md) - app demo uses the dark theme - [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md) - added a Demo Info panel which describes this app - [Dashboard](https://www.adaptabletools.com/docs/ui-dashboard/index.md) - set the app's Title, provided some buttons including a custom Info button, which opens Demo Info panel described above - [Status Bar](https://www.adaptabletools.com/docs/ui-status-bar/index.md) - added Layout and Cell Summary panels - lots of [Column Formats](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) - particularly on the number columns - a [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - called `Sector Pnl` which aggregates all the Postions, grouped by Sector - 2 [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md): `Table Layout` and `Sector Layout` (with Row Grouping and Aggregations) - [Badge Style](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md) - on the Sector column - [Sparkline Column](https://www.adaptabletools.com/docs/handbook-styled-column-sparkline/index.md) - on the Performance column - in [Context Menu Options](https://www.adaptabletools.com/docs/ui-context-menu/index.md) - provided implementation for `customContextMenu` so only one item appears in Ticker Column's context menu ### Putting It All Together This is the full definition of the FDC3 Options used in the demo: ```ts {1} fdc3Options: { enableLogging: true, // Create a single Data Mapping - to FDC3 Instrument Context // Use `Name` column (defined by '_colId') as the Instrument Name // Use the `Symbol` field (defined by '_field') to map to Ticker (in `id` prop) gridDataContextMapping: { 'fdc3.instrument': { name: '_colId.Name', id: { ticker: '_field.Symbol', }, }, }, intents: { raises: { // Raise 3 Intents: `ViewChart`, `ViewNews` and `ViewInstument` // Create an FDC3 Action Button for all 3 Intents // Each button will be rendered in the default FDC3 Action Column // Note: All 3 Intents use the mapping that was created in `gridDataContextMapping` ViewChart: [ { contextType: 'fdc3.instrument', actionButton: { id: 'viewChartBtn', tooltip: 'Raise: ViewChart', icon: '_defaultFdc3', buttonStyle: { tone: 'info', variant: 'outlined', }, }, }, ], ViewNews: [ { contextType: 'fdc3.instrument', actionButton: { id: 'viewNewsBtn', tooltip: 'Raise: ViewNews', icon: '_defaultFdc3', buttonStyle: { variant: 'outlined', tone: 'warning', }, }, }, ], ViewInstrument: [ { contextType: 'fdc3.instrument', actionButton: { id: 'viewInstrumentBtn', tooltip: 'Raise: ViewInstrument', icon: { name: 'visibility-on', }, buttonStyle: { tone: 'error', variant: 'outlined', }, }, }, ], custom: { // Raise the Custom `GetPrice` Intent - using a bespoke FDC3 Action Column // When we receive a Price, display it in the column (instead of the button) GetPrice: [ { contextType: 'fdc3.instrument', // Provide a bespoke Action Column definition actionColumn: { columnId: 'fdc3GetPriceColumn', friendlyName: 'Get Price', button: { id: 'GetPriceButton', label: (button, context) => { const price = priceMap.get(context.rowData.Symbol); return !!price ? `$ ${price}` : 'Get Price'; }, icon: (button, context) => { const price = priceMap.get(context.rowData.Symbol); return !price ? { name: 'quote', } : null; }, tooltip: (button, context) => { return `Get Price Info for ${context.rowData.Symbol}`; }, buttonStyle: (button, context) => { return priceMap.has(context.rowData.Symbol) ? { tone: 'success', variant: 'text', } : { tone: 'info', variant: 'outlined', }; }, disabled: (button, context) => { return priceMap.has(context.rowData.Symbol); }, }, }, // Handle the intent resolution by showing the returned Price in the Column handleIntentResolution: async ( handleResolutionContext: HandleFdc3IntentResolutionContext, ) => { const intentResult = await handleResolutionContext.intentResolution.getResult(); if (!intentResult?.type) { return; } const adaptableApi: AdaptableApi = handleResolutionContext.adaptableApi; const contextData = intentResult as Fdc3CustomContext; const ticker = contextData.id?.ticker; const price = contextData.price; if (ticker) { priceMap.set(ticker, price); } adaptableApi.gridApi.refreshColumn('fdc3GetPriceColumn'); }, }, ], }, }, // listen for the 'fdc3.instrument' Context listensFor: ['ViewInstrument'], // handle the Intent received handleIntent: (handleFDC3Context: HandleFdc3Context) => { const adaptableApi: AdaptableApi = handleFDC3Context.adaptableApi; const ticker = handleFDC3Context.context.id?.ticker; const upperTicker = ticker.toUpperCase(); // Create Row Highlight object, then jump to row and highlight it const rowHighlightInfo: RowHighlightInfo = { primaryKeyValue: upperTicker, timeout: 5000, highlightStyle: { BackColor: 'Yellow', ForeColor: 'Black', }, }; adaptableApi.gridApi.jumpToRow(upperTicker); adaptableApi.gridApi.highlightRow(rowHighlightInfo); // Display `Info` System Status Message with details of Intent received adaptableApi.systemStatusApi.setInfoSystemStatus( 'Intent Received: ' + upperTicker, JSON.stringify(handleFDC3Context.context), ); }, }, contexts: { // Broadcast FDC3 Instrument in 2 ways: // using a Context Menu Item in Ticker and Name columns // via a FDC3 Action Button (which will be rendered in the default FDC3 Action Column) // Note: The Context uses the mapping that was created in `gridDataContextMapping` broadcasts: { 'fdc3.instrument': { contextMenu: { columnIds: ['Ticker', 'Name'], icon: '_defaultFdc3', }, actionButton: { id: 'broadcastInstrumentBtn', icon: { name: 'broadcast' }, tooltip: `Broadcast: Instrument`, buttonStyle: { tone: 'success', variant: 'outlined', }, }, }, }, // listen for the `ViewInstrument` Context listensFor: ['fdc3.instrument'], // handle the Context received handleContext: (handleFDC3Context: HandleFdc3Context) => { if (handleFDC3Context.context.type === 'fdc3.instrument') { const adaptableApi: AdaptableApi = handleFDC3Context.adaptableApi; const ticker = handleFDC3Context.context.id?.ticker; // Filter the Grid using the received Ticker adaptableApi.filterApi.columnFilterApi.setColumnFilterForColumn('Ticker', { PredicateId: 'Is', PredicateInputs: [handleFDC3Context.context.id?.ticker], }); // Display `Success` System Status Message with details of Context received adaptableApi.systemStatusApi.setSuccessSystemStatus( 'Context Received: ' + ticker, JSON.stringify(handleFDC3Context.context), ); } }, }, // Narrow width of Default Action Column actionColumnDefaultConfiguration: { width: 150, }, }, ``` --- # FDC3 Intents Canonical page: https://www.adaptabletools.com/docs/handbook-fdc3-intents - This AdapTable Help Page is being actively updated - AdapTable has just upgraded to FDC3 2.0 and we are working on updating the documentation - AdapTable fully supports FDC3 Intents; users can: - Raise Intents - Listen for Intents - Create Custom Intents Intents are FDC3 **actions** that a user wants to perform or react to. AdapTable supports Intents through the `intents` property in FDC3 Options. This object is of type [`Fdc3IntentOptions`](https://www.adaptabletools.com/docs/reference/fdc3intentoptions.md) which contains these properties: | Property | Type | Description | | --- | --- | --- | | [handleIntent](https://www.adaptabletools.com/docs/reference/fdc3intentoptions.md#handleintent) | `(context: `[`HandleFdc3IntentContext`](https://www.adaptabletools.com/docs/reference/handlefdc3intentcontext.md)`) => Promise \| void` | Handles incoming Intents (standard and custom) | | [handleIntentResolution](https://www.adaptabletools.com/docs/reference/fdc3intentoptions.md#handleintentresolution) | `(context: `[`HandleFdc3IntentResolutionContext`](https://www.adaptabletools.com/docs/reference/handlefdc3intentresolutioncontext.md)`) => Promise` | Handles the IntentResolution that a raised Intent might return | | [listensFor](https://www.adaptabletools.com/docs/reference/fdc3intentoptions.md#listensfor) | `Intent[]` | Subscribe to given standard Intent(s) | | [raises](https://www.adaptabletools.com/docs/reference/fdc3intentoptions.md#raises) | [`RaiseIntentConfiguration`](https://www.adaptabletools.com/docs/reference/raiseintentconfiguration.md) | Raises given standard Intent(s) on various Grid Actions | As can be seen, users are able both to **Raise** and **Listen For** FDC3 Intents. ## Available Intents The FDC3 Intents supported by AdapTable (and the Contexts they can be used in) are as follows: | FDC3 Intent | Available Contexts | | ---------------------------------------------------------------------------- | ------------------------------------------------------------ | | [StartCall](https://fdc3.finos.org/docs/intents/ref/StartCall) | Contact, ContactList | | [StartChat](https://fdc3.finos.org/docs/intents/ref/StartChat) | Contact, ContactList, ChatInitSettings | | [StartEmail](https://fdc3.finos.org/docs/intents/ref/StartEmail) | Email | | [ViewAnalysis](https://fdc3.finos.org/docs/intents/ref/ViewAnalysis) | Instrument, Organization, Portfolio | | [ViewChart](https://fdc3.finos.org/docs/intents/ref/ViewChart) | Chart, Instrument, Organization, Portfolio, Position | | [ViewContact](https://fdc3.finos.org/docs/intents/ref/ViewContact) | Contact | | [ViewHoldings](https://fdc3.finos.org/docs/intents/ref/ViewHoldings) | Instrument, InstrumentList, Organization | | [ViewInstrument](https://fdc3.finos.org/docs/intents/ref/ViewInstrument) | Instrument | | [ViewInteractions](https://fdc3.finos.org/docs/intents/ref/ViewInteractions) | Contact, InstrumentList, Organization | | [ViewNews](https://fdc3.finos.org/docs/intents/ref/ViewNews) | Country, Instrument, InstrumentList, Organization, Portfolio | | [ViewOrders](https://fdc3.finos.org/docs/intents/ref/ViewOrders) | Contact, InstrumentList, Organization | | [ViewProfile](https://fdc3.finos.org/docs/intents/ref/ViewProfile) | Contact, Organization | | [ViewQuote](https://fdc3.finos.org/docs/intents/ref/ViewQuote) | Instrument | | [ViewResearch](https://fdc3.finos.org/docs/intents/ref/ViewResearch) | Contact, InstrumentList, Organization | ## Raising Intents Intents are raised using the `raises` property in the `intents` section of FDC3 Options. Each Intent to raise is listed by type (e.g. `ViewQuote`) and followed by the Intent-raising behaviour. - Make sure **all intents** you raise are referenced in the `gridDataContextMapping` property of FDC3 Options - This is a required step which AdapTable uses to [map columns and fields to FDC3 objects](https://www.adaptabletools.com/docs/u/handbook-fdc3-mappings) This behaviour can take one of 2 forms: - a [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) entry - an [FDC3 Action Column](https://www.adaptabletools.com/docs/u/handbook-fdc3-ui-components) (either a button or full Column definition can be provided) It is possible to raise an Intent using **both** [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) and [FDC3 Action Column](https://www.adaptabletools.com/docs/u/handbook-fdc3-ui-components) ### `raises` Raises given standard Intent(s) on various Grid Actions [`RaiseIntentConfiguration`](https://www.adaptabletools.com/docs/reference/raiseintentconfiguration.md) Property which defines which FDC3 Intents can be raised. It provides an object of type [`RaiseIntentConfiguration`](https://www.adaptabletools.com/docs/reference/raiseintentconfiguration.md). It is essentially a collection of [`RaiseIntentConfig`](https://www.adaptabletools.com/docs/reference/raiseintentconfig.md) each of which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [actionButton](https://www.adaptabletools.com/docs/reference/raiseintentconfig.md#actionbutton) | [`Fdc3AdaptableButton`](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md) | Definition of Action Button (to be put in default FDC3 Action Column) | | [actionColumn](https://www.adaptabletools.com/docs/reference/raiseintentconfig.md#actioncolumn) | `\{ columnId: string; friendlyName?: string; button: `[`Fdc3AdaptableButton`](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md)`; width?: number; \}` | Custom FDC3 Action Column definition for the Intent | | [contextMenu](https://www.adaptabletools.com/docs/reference/raiseintentconfig.md#contextmenu) | `\{ columnIds: string[]; icon?: '_defaultFdc3' \| `[`AdaptableIcon`](https://www.adaptabletools.com/docs/reference/adaptableicon.md)`; \}` | Columns to display a 'Raise Intent' Context Menu item | | [contextType](https://www.adaptabletools.com/docs/reference/raiseintentconfig.md#contexttype) | `ContextType` | Key of Context being Raised | | [handleIntentResolution](https://www.adaptabletools.com/docs/reference/raiseintentconfig.md#handleintentresolution) | `(context: `[`HandleFdc3IntentResolutionContext`](https://www.adaptabletools.com/docs/reference/handlefdc3intentresolutioncontext.md)`) => Promise` | Handles the IntentResolution for this specific raise intent configuration | Each Intent Config has a Key which is the Intent being raised (e.g. `ViewQuote`, `StartCall`). It includes 2 main elements: - **context type** - the `contextType` property specifies which context to use (e.g. fdc3.instrument) - This context should be referenced in the `gridDataContextMapping` property of FDC3 Options - See [Mapping columns and fields to FDC3 objects](https://www.adaptabletools.com/docs/u/handbook-fdc3-mappings) for more information - **behaviour** - how to Raise the Intent (i.e. via the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) or using an [Action Column / Button](https://www.adaptabletools.com/docs/handbook-action-column/index.md)) See [FDC3 Action Columns and Buttons](https://www.adaptabletools.com/docs/handbook-fdc3-ui-components/index.md) for full details on how these Buttons and Action Columns are rendered ```tsx {2,3,4,20} fdc3Options: { intents: { raises: { ViewQuote: [ { contextType: 'fdc3.instrument', contextMenu: { columnIds: ['ticker'], }, actionButton: { id: 'ViewQuoteButton', label: 'View Quote', icon: { name: 'info', }, tooltip: '_defaultFdc3', }, }, ], ViewInstrument: [ { contextType: 'fdc3.instrument', contextMenu: { columnIds: ['instrument', 'ticker'], }, actionColumn: { columnId: 'fdc3ViewInstrumentColumn', friendlyName: 'FDC3: ViewInstrument', button: { id: 'ViewInstrumentButton', label: '_defaultFdc3', tooltip: '_defaultFdc3', }, }, }, ], }, }, }, ``` ## Listening for Intents Listening for Intents from external applications is done in 2 stages: Both of these steps uses a property in the `intents` section of FDC3 Options - all Intents to handle are listed in the `listensFor` property - an implementation is given for the `handleIntent` function property ### `listensFor` Subscribe to given standard Intent(s) [`Fdc3IntentType`](https://www.adaptabletools.com/docs/reference/fdc3intenttype) Lists which FDC3 Intents are listened for. The array is of type [`Fdc3IntentType`](https://www.adaptabletools.com/docs/reference/fdc3intenttype) which are FDC3 strings (e.g. `ViewInstrument`, `StartCall`) ```tsx {2,3} contexts: { listensFor: ['ViewQuote', 'ViewInstrument', 'StartCall'], handleIntent: (fdc3IntentContext: HandleFdc3IntentContext) => { console.log(`Received context: `, fdc3IntentContext); }, }, ``` These Intents are then typically handled in the `handleIntent` function property (see below). ## Handling Intents Incoming FDC3 Intents is handled by the `handleIntent` property. ### `handleIntent` Handles incoming Intents (standard and custom) Property used to handle incoming FDC3 Intents. Make sure that the Intent is listed in the `listensFor` property - also in the `intents` object ```tsx handleIntent?: (context: HandleFdc3IntentContext) => Promise | void; ``` As can be seen the function: - receives an object of type [`HandleFdc3IntentContext`](https://www.adaptabletools.com/docs/reference/handlefdc3intentcontext.md) which simply contains the FDC3 Intent - asynchronously returns FDC3's `IntentResult` object (which is of type `Context | Channel | void`) ```tsx {2} contexts: { handleContext: (context: HandleFdc3Context) => { console.log(`Received context: `, eventInfo); }, }, ``` --- # FDC3 Data Grid Context Mappings Canonical page: https://www.adaptabletools.com/docs/handbook-fdc3-mappings - FDC3 Mappings define which columns / fields should be used for which FDC3 objects - It enables a data-first approach to using FDC3 which is incredibly flexible Grid Data Mappings provide the "glue" to map AG Grid's data and columns to required FDC3 behaviour. AdapTable looks at the mappings to work out which columns to use when creating Intents and Contexts. - Previously AdapTable provided FDC3 Columns which defined which contexts to use - These have been replaced with mappings which allow for a richer and more intuitive "data-first" approach Mappings are provided in the `gridDataContextMapping` property of FDC3 Options. ### `gridDataContextMapping` Maps Context Type to AdapTable Grid Data [`GridDataContextMapping`](https://www.adaptabletools.com/docs/reference/griddatacontextmapping.md) This property is used to tell AdapTable which columns and fields should be used in FDC3 Context. These are then used when raising Intents or broadcasting Context. The [`GridDataContextMapping`](https://www.adaptabletools.com/docs/reference/griddatacontextmapping.md) object provides the FDC3 Context. **Grid Data Context Mapping** ֵEach Grid Data Context Mapping has the same structure (though the details will differ according to the Context type): - a **key** - a formal FDC3 type (e.g. `fdc3.instrument` or `fdc3.currency`) - an associated **FDC3 Context object** The FDC3 Context object contains 2 properties: - `name` - an **FDC3 Data Mapping** - `id` - an object which can contain multiple properties. Each of the properties will provide a FDC3 Data Mapping **FDC3 Data Mapping** Each FDC3 Data Mapping tells AdapTable where to find the data to build the Context. The Data Mapping can always be one of 2 types of object: - a **Column** - either AdapTable or AG Grid; using the `_colId` prefix (e.g. `_colId.instrument`) - a **Field** in the Grid's data source; using the `_field` prefix (e.g. `_field.ticker`) ```tsx {1} gridDataContextMapping: { 'fdc3.instrument': { name: '_colId.instrument', id: { ticker: '_colId.ticker', BBG: '_field.bbgId', }, }, } ``` ### Creating FDC3 Grid Data Mappings Lets look in more detail at the example above - which uses a `fdc3.instrument`. We therefore provide an FDC3 Instrument Context (see formal object definition [here](https://fdc3.finos.org/docs/context/ref/Instrument)) and then reference it to raise Intents and broadcast Contexts. First provide the Mapping using the `gridDataContextMapping` property Then define each Mapping as required. The key is always a FDC3 Context type. In this example its an Instrument defined as `fdc3.instrument` ```tsx [[1, 1, "gridDataContextMapping"], [1,2, "'fdc3.instrument'"]] gridDataContextMapping: { 'fdc3.instrument': { name: '_colId.instrument', id: { ticker: '_colId.ticker', BBG: '_field.bbgId', }, }, ``` Each mapping has 2 properties: - `name` - typically one column - `id` - an object with multiple properties, each will be a Data Mapping In this example of fdc3.instrument, the id can include many different properties, and we have provided 2 (`ticker` and `BBG`) ```tsx [[2, 3, "name"], [2, 4, "id"]] gridDataContextMapping: { 'fdc3.instrument': { name: '_colId.instrument', id: { ticker: '_colId.ticker', BBG: '_field.bbgId', }, }, ``` Map Columns or Fields to each Data Mapping as required. Columns use the prefix `_colId` - here we reference 2 Columns: - `Instrument` - which we provide for `name` property - `Ticker` - which we provide for the `ticker` property Fields in the DataSource use the prefix `_field` - as in this example: - `bbgId` - which we provide for the `BBG` property ```tsx [[3, 3, "'_colId.instrument'"], [3, 5, "'_colId.ticker'"] ,[3, 6, "'_field.bbgId'"]] gridDataContextMapping: { 'fdc3.instrument': { name: '_colId.instrument', id: { ticker: '_colId.ticker', BBG: '_field.bbgId', }, }, ``` Now we can use it to manage Intents. We are able to: - **raise** the `ViewInstrument` Intent We use both Context Menu and Action Column - **listen for** the `ViewQuote` Intent In both cases, AdapTable will automatically use the mapping supplied in Step 1 when providing context. ```tsx [[4, 1, "intents"], [4, 2, "raises"], [4, 16, "listensFor"]] intents: { raises: { ViewInstrument: [ { contextType: 'fdc3.instrument', contextMenu: { columnIds: ['ticker'], }, actionButton: { id: 'viewInstrumentButton', label: 'View Instrument', }, }, ], }, listensFor: ['ViewQuote', 'ViewInstrument'], }, ``` Similarly we can use the mapping with Contexts. We are able to: - **broadcast** Instrument Context Again, we use both Context Menu and Action Column - **listen for** the `fdc3.instrument` context being broadcast in other applications And, again, AdapTable will automatically use the mapping supplied in Step 1 when providing context. ```tsx [[5, 1, "contexts"], [5, 2, "broadcasts"], [5, 13, "listensFor"]] contexts: { broadcasts: { 'fdc3.instrument': { contextMenu: { columnIds: ['ticker'], }, actionButton: { id: 'broadCastInstrumentButton', label: 'Broadcast Ticker Info', }, }, }, listensFor: ['fdc3.instrument'], }, ``` ## Available Contexts The following FDC3 2.0 Contexts can be provided in Grid Data Context Mappings: Click the link to see full details of the Context in the FDC3 2.0 documentation - [Chart](https://fdc3.finos.org/docs/context/ref/Chart) - [ChatInitSettings](https://fdc3.finos.org/docs/context/ref/ChatInitSettings) - [Contact](https://fdc3.finos.org/docs/context/ref/Contact) - [ContactList](https://fdc3.finos.org/docs/context/ref/ContactList) - [Country](https://fdc3.finos.org/docs/context/ref/Country) - [Currency](https://fdc3.finos.org/docs/context/ref/Currency) - [Email](https://fdc3.finos.org/docs/context/ref/Chart) - [Instrument](https://fdc3.finos.org/docs/context/ref/Instrument) - [InstrumentList](https://fdc3.finos.org/docs/context/ref/InstrumentList) - [Organization](https://fdc3.finos.org/docs/context/ref/Organization) - [Portfolio](https://fdc3.finos.org/docs/context/ref/Portfolio) - [Position](https://fdc3.finos.org/docs/context/ref/Position) - [TimeRange](https://fdc3.finos.org/docs/context/ref/TimeRange) - [Valuation](https://fdc3.finos.org/docs/context/ref/Valuation) --- # FDC3 Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-fdc3-technical-reference - FDC3 Options are to used configure FDC3 - FDC3 API provides runtime programmatic access to FDC3 - FDC3 Message Event is fired whenver an FDC3 Message is sent or received ------------- ## FDC3 Options The [`FDC3 Options`](https://www.adaptabletools.com/docs/reference/fdc3options.md) section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) is the primary way to configure and manage FDC3: | Property | Type | Description | Default | | --- | --- | --- | --- | | [actionColumnDefaultConfiguration](https://www.adaptabletools.com/docs/reference/fdc3options.md#actioncolumndefaultconfiguration) | [`ActionColumnDefaultConfiguration`](https://www.adaptabletools.com/docs/reference/actioncolumndefaultconfiguration.md) | Configures the default FDC3 Actions column | columnId: 'fdc3ActionColumn', headerName: 'FDC3 Actions', width: 200, resizable: true, movable: false, rowScope: ExcludeDataRows: false, ExcludeGroupRows: true, ExcludeSummaryRows: true, ExcludeTotalRows: true | | [contexts](https://www.adaptabletools.com/docs/reference/fdc3options.md#contexts) | [`Fdc3ContextOptions`](https://www.adaptabletools.com/docs/reference/fdc3contextoptions.md) | Configures FDC3 standard Contexts that AdapTable will listen for and broadcast | | | [enableLogging](https://www.adaptabletools.com/docs/reference/fdc3options.md#enablelogging) | `boolean` | Enable logging message exchanges to Console | false | | [gridDataContextMapping](https://www.adaptabletools.com/docs/reference/fdc3options.md#griddatacontextmapping) | [`GridDataContextMapping`](https://www.adaptabletools.com/docs/reference/griddatacontextmapping.md) | Maps Context Type to AdapTable Grid Data | | | [intents](https://www.adaptabletools.com/docs/reference/fdc3options.md#intents) | [`Fdc3IntentOptions`](https://www.adaptabletools.com/docs/reference/fdc3intentoptions.md) | Configures FDC3 standard Intents that AdapTable will listen for and raise | | | [resolveContextData](https://www.adaptabletools.com/docs/reference/fdc3options.md#resolvecontextdata) | `(context: `[`ResolveContextDataContext`](https://www.adaptabletools.com/docs/reference/resolvecontextdatacontext.md)`) => Context` | Builds Context Data (useful for postprocessing Context Data mapped from Grid data) | | | [uiControlsDefaultConfiguration](https://www.adaptabletools.com/docs/reference/fdc3options.md#uicontrolsdefaultconfiguration) | `\{ contexts?: \{ [contextName in StandardContextType]?: `[`UIControlConfig`](https://www.adaptabletools.com/docs/reference/uicontrolconfig.md)`; \}; intents?: \{ [intentName in StandardIntent]?: `[`UIControlConfig`](https://www.adaptabletools.com/docs/reference/uicontrolconfig.md)`; \}; \}` | Customises FDC3 UI Controls | contexts: , intents: | ### FDC3 Intent Options The [`FDC3 Intent Options`](https://www.adaptabletools.com/docs/reference/fdc3intentoptions.md) property handles FDC3 Intents behaviour: | Property | Type | Description | | --- | --- | --- | | [handleIntent](https://www.adaptabletools.com/docs/reference/fdc3intentoptions.md#handleintent) | `(context: `[`HandleFdc3IntentContext`](https://www.adaptabletools.com/docs/reference/handlefdc3intentcontext.md)`) => Promise \| void` | Handles incoming Intents (standard and custom) | | [handleIntentResolution](https://www.adaptabletools.com/docs/reference/fdc3intentoptions.md#handleintentresolution) | `(context: `[`HandleFdc3IntentResolutionContext`](https://www.adaptabletools.com/docs/reference/handlefdc3intentresolutioncontext.md)`) => Promise` | Handles the IntentResolution that a raised Intent might return | | [listensFor](https://www.adaptabletools.com/docs/reference/fdc3intentoptions.md#listensfor) | `Intent[]` | Subscribe to given standard Intent(s) | | [raises](https://www.adaptabletools.com/docs/reference/fdc3intentoptions.md#raises) | [`RaiseIntentConfiguration`](https://www.adaptabletools.com/docs/reference/raiseintentconfiguration.md) | Raises given standard Intent(s) on various Grid Actions | ### FDC3 Context Options The [`FDC3 Context Options`](https://www.adaptabletools.com/docs/reference/fdc3contextoptions.md) property handles FDC3 Context behaviour: | Property | Type | Description | | --- | --- | --- | | [broadcasts](https://www.adaptabletools.com/docs/reference/fdc3contextoptions.md#broadcasts) | [`BroadcastConfiguration`](https://www.adaptabletools.com/docs/reference/broadcastconfiguration.md) | Broadcasts given standard Context(s) on various Grid Actions | | [handleContext](https://www.adaptabletools.com/docs/reference/fdc3contextoptions.md#handlecontext) | `(context: `[`HandleFdc3Context`](https://www.adaptabletools.com/docs/reference/handlefdc3context.md)`) => void` | Handles incoming Contexts (standard and custom) | | [listensFor](https://www.adaptabletools.com/docs/reference/fdc3contextoptions.md#listensfor) | `ContextType[]` | Subscribe to given standard Context(s) | ------------- ## FDC3 API The [`FDC3 API`](https://www.adaptabletools.com/docs/reference/fdc3api.md) section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) contains functions relating to [FDC3](https://www.adaptabletools.com/docs/handbook-fdc3/index.md): | Method | Returns | Description | | --- | --- | --- | | [broadcastFromPrimaryKey(primaryKeyValue, contextType, channel)](https://www.adaptabletools.com/docs/reference/fdc3api.md#broadcastfromprimarykey) | `Promise \| undefined` | Broadcasts the given Context from the given Row Node with the given Primary Key Value | | [broadcastFromRow(rowNode, contextType, channel)](https://www.adaptabletools.com/docs/reference/fdc3api.md#broadcastfromrow) | `Promise` | Broadcasts the given Context from the given Row Node | | [buildContextDataForPrimaryKey(contextType, primaryKeyValue)](https://www.adaptabletools.com/docs/reference/fdc3api.md#buildcontextdataforprimarykey) | `Context \| undefined` | Builds FDC3 Context Data based on the given Context Type and the Row Node with the given Primary Key Value | | [buildContextDataFromRow(contextType, rowNode)](https://www.adaptabletools.com/docs/reference/fdc3api.md#buildcontextdatafromrow) | `Context` | Builds FDC3 Context Data based on the given Context Type and Row Node | | [getContextLabel(contextType)](https://www.adaptabletools.com/docs/reference/fdc3api.md#getcontextlabel) | `string` | Returns the human-friendly label for the given Context Type | | [getDesktopAgent()](https://www.adaptabletools.com/docs/reference/fdc3api.md#getdesktopagent) | `DesktopAgent` | Returns the FDC3 Desktop Agent | | [isStandardContextType(contextType)](https://www.adaptabletools.com/docs/reference/fdc3api.md#isstandardcontexttype) | `boolean` | Checks if the given Context Type is a FDC3 standard Context Type | | [isStandardIntentType(intentType)](https://www.adaptabletools.com/docs/reference/fdc3api.md#isstandardintenttype) | `boolean` | Checks if the given Intent is a FDC3 standard Intent Type | | [raiseIntentForContextFromPrimaryKey(primaryKeyValue, contextType, appIdentifier)](https://www.adaptabletools.com/docs/reference/fdc3api.md#raiseintentforcontextfromprimarykey) | `Promise \| undefined` | Finds and raises an Intent based on the given Context from the given Row Node with the given Primary Key Value | | [raiseIntentForContextFromRow(rowNode, contextType, appIdentifier)](https://www.adaptabletools.com/docs/reference/fdc3api.md#raiseintentforcontextfromrow) | `Promise` | Finds and raises an Intent based on the given Context from the given Row Node | | [raiseIntentFromPrimaryKey(primaryKeyValue, intent, contextType, appIdentifier)](https://www.adaptabletools.com/docs/reference/fdc3api.md#raiseintentfromprimarykey) | `Promise \| undefined` | Raises an Intent with the given Context from the given Row Node with the given Primary Key Value | | [raiseIntentFromRow(rowNode, intent, contextType, appIdentifier)](https://www.adaptabletools.com/docs/reference/fdc3api.md#raiseintentfromrow) | `Promise` | Raises an Intent with the given Context from the given Row Node | ---------------- ## FDC3 Message Event The FDC3 Message Event is triggered whenever a FDC3 Message is sent or received. ### Fdc3MessageInfo There are 2 different Message Info objects that the Event provides depending whether the FDC3 message was sent or received: - The [`Fdc3MessageSentInfo`](https://www.adaptabletools.com/docs/reference/fdc3messagesentinfo.md) object provides details of **sent** messages: | Property | Type | Description | | --- | --- | --- | | [app](https://www.adaptabletools.com/docs/reference/fdc3messagesentinfo.md#app) | `AppIdentifier` | Target application for the message | | [context](https://www.adaptabletools.com/docs/reference/fdc3messagesentinfo.md#context) | `Context` | Full FDC3 Context for object related to the Event | | [direction](https://www.adaptabletools.com/docs/reference/fdc3messagesentinfo.md#direction) | `'sent'` | Direction - always 'sent' | | [eventType](https://www.adaptabletools.com/docs/reference/fdc3messagesentinfo.md#eventtype) | `'RaiseIntent' \| 'RaiseIntentForContext' \| 'BroadcastMessage'` | Event Type: `RaiseIntent`, `RaiseIntentForContext, `BroadcastMessage | | [intent](https://www.adaptabletools.com/docs/reference/fdc3messagesentinfo.md#intent) | `Intent` | FDC3 Intent which caused Event to fire (if type is `RaiseIntent`) | | [adaptableContext](https://www.adaptabletools.com/docs/reference/fdc3messagesentinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | - The [`Fdc3MessageReceivedInfo`](https://www.adaptabletools.com/docs/reference/fdc3mefdc3messagereceivedinfossagesentinfo) object provides details of **received** messages: | Property | Type | Description | | --- | --- | --- | | [context](https://www.adaptabletools.com/docs/reference/fdc3messagereceivedinfo.md#context) | `Context` | Full FDC3 Context for object related to the Event | | [direction](https://www.adaptabletools.com/docs/reference/fdc3messagereceivedinfo.md#direction) | `'received'` | Direction - always 'received' | | [eventType](https://www.adaptabletools.com/docs/reference/fdc3messagereceivedinfo.md#eventtype) | `'IntentRaised' \| 'ContextBroadcast'` | EventType: `IntentRaised`, `ContextBroadcast` | | [intent](https://www.adaptabletools.com/docs/reference/fdc3messagereceivedinfo.md#intent) | `Intent` | FDC3 Intent which caused Event to fire (if type is `IntentRaised`) | | [metadata](https://www.adaptabletools.com/docs/reference/fdc3messagereceivedinfo.md#metadata) | `ContextMetadata` | Metadata associated with the FDC3 Context | | [adaptableContext](https://www.adaptabletools.com/docs/reference/fdc3messagereceivedinfo.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('Fdc3Message', (eventInfo: Fdc3MessageSentInfo) => { // do something with the info }); api.eventApi.on('Fdc3Message', (eventInfo: Fdc3MessageReceivedInfo) => { // do something with the info }); ``` --- # FDC3 UI Components Canonical page: https://www.adaptabletools.com/docs/handbook-fdc3-ui-components - This AdapTable Help Page is being actively updated - AdapTable has just upgraded to FDC3 2.0 and we are working on updating the documentation - It is easy for developers to raise FDC3 Intents or Broadcast FDC3 Context using the AdapTable UI - Both can be provided via FDC3 Menu Items that appear in the **Context Menu** - Or they can be available using **FDC3 Action Columns** which can be: - created dynamically by AdapTable using developer-provided Button definitions - be full FDC3 Action Column definitions - supplied by developers AdapTable makes it easy for developers to configure the AdapTable UI to perform FDC3-related actions. These FDC3-related actions will most typically be to: - [Raise FDC3 Intents](https://www.adaptabletools.com/docs/handbook-fdc3-intents/index.md) - [Broadcast FDC3 Context](https://www.adaptabletools.com/docs/handbook-fdc3-context/index.md) In particular 2 areas of UI Components are available: - Context Menu - FDC3 Action Columns ## Context Menu Items AdapTable leverages the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) to make it easy for users to raise Intents or broadcast Context. ```tsx {6,7,8,17,18,19} intents: { raises: { ViewResearch: [ { contextType: 'fdc3.instrument', contextMenu: { columnIds: ['instrument', 'counterparty'], icon: '_defaultFdc3', }, }, ], } }, contexts: { broadcasts: { 'fdc3.currency': { contextMenu: { columnIds: ['currency'], icon: '_defaultFdc3', }, }, } }, ``` ## FDC3 Action Columns AdapTable makes it easy for developers to provide dedicated Buttons to perform FDC3-related actions. Developers can provide buttons in one 2 ways: - as standard [Adaptable Button](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md) definitions (and AdapTable creates the Action Column) - inside a bespoke [Action Column](https://www.adaptabletools.com/docs/handbook-action-column/index.md) definition This approach allows for as many FDC3 Action Columns as required and for full flexibility over look and feel ### FDC3 Buttons The more straightforward approach is to define FDC3 Buttons. These buttons are of type [`Fdc3AdaptableButton`](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md) - a specialist, reduced form of the standard [Adaptable Button](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md) containing these poperties: | Property | Type | Description | | --- | --- | --- | | [buttonStyle](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md#buttonstyle) | [`ButtonStyle`](https://www.adaptabletools.com/docs/reference/buttonstyle.md)` \| ((button: `[`Fdc3AdaptableButton`](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md)`, context: `[`Fdc3ButtonContext`](https://www.adaptabletools.com/docs/reference/fdc3buttoncontext.md)`) => `[`ButtonStyle`](https://www.adaptabletools.com/docs/reference/buttonstyle.md)`)` | Button's Style; can be object or function that provides `ButtonStyle` object | | [disabled](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md#disabled) | `(button: `[`Fdc3AdaptableButton`](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md)`, context: `[`Fdc3ButtonContext`](https://www.adaptabletools.com/docs/reference/fdc3buttoncontext.md)`) => boolean` | Function to disable / enable button based on evaluation result | | [hidden](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md#hidden) | `(button: `[`Fdc3AdaptableButton`](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md)`, context: `[`Fdc3ButtonContext`](https://www.adaptabletools.com/docs/reference/fdc3buttoncontext.md)`) => boolean` | Function to hide the Button | | [icon](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md#icon) | `'_defaultFdc3' \| `[`AdaptableIcon`](https://www.adaptabletools.com/docs/reference/adaptableicon.md)` \| ((button: `[`Fdc3AdaptableButton`](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md)`, context: `[`Fdc3ButtonContext`](https://www.adaptabletools.com/docs/reference/fdc3buttoncontext.md)`) => `[`AdaptableIcon`](https://www.adaptabletools.com/docs/reference/adaptableicon.md)`)` | Button's Icon; can be object or function that provides `AdaptableIcon` object | | [id](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md#id) | `string` | Unique id for the button | | [label](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md#label) | `'_defaultFdc3' \| string \| ((button: `[`Fdc3AdaptableButton`](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md)`, context: `[`Fdc3ButtonContext`](https://www.adaptabletools.com/docs/reference/fdc3buttoncontext.md)`) => string)` | Button's Label; can be string or function that provides string | | [tooltip](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md#tooltip) | `'_defaultFdc3' \| string \| ((button: `[`Fdc3AdaptableButton`](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md)`, context: `[`Fdc3ButtonContext`](https://www.adaptabletools.com/docs/reference/fdc3buttoncontext.md)`) => string)` | Button's Tooltip; can be string or function that provides string | AdapTable will dynamically render these buttons inside an FDC3 Action Column. The Button definition is the same for [Raising FDC3 Intents](https://www.adaptabletools.com/docs/handbook-fdc3-intents/index.md) and [Broadcasting FDC3 Context](https://www.adaptabletools.com/docs/handbook-fdc3-context/index.md) Like all [Adaptable Buttons](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md), FDC3 Buttons can be provided with custom Label, Style, Icon and Tooltip. - As a convenience, AdapTable provides [default values for Icon and Tooltip properties](#default-button-values) to be rendered as required - These defaults themselves can be overridden by developers if required ```tsx {7,8,9,10,11,19,20,21,22} fdc3Options: { intents: { raises: { ViewQuote: [ { contextType: 'fdc3.instrument', actionButton: { id: 'ViewQuoteButton', label: 'View Quote', icon: '_defaultFdc3', tooltip: '_defaultFdc3', }, }, ], }, contexts: { broadcasts: { 'fdc3.currency': { actionButton: { id: 'BroadCastCurrencyButton', icon: '_defaultFdc3', tooltip: '_defaultFdc3', }, }, }, }, ``` ### Default FDC3 Action Column AdapTable creates a FDC3 Action Column automatically in which to render any defined FDC3 Buttons. The Column has the Id `fdc3ActionColumn` and can be used like any other [Action Column](https://www.adaptabletools.com/docs/handbook-action-column/index.md) in AdapTable. If you wish this Action Column to be visible it is your responsibility to list it in the relevant [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) The Default Action Column can itself be configured by developers using the `actionColumnDefaultConfiguration` property in FDC3 Options. ### `actionColumnDefaultConfiguration` Configures the default FDC3 Actions column [`ActionColumnDefaultConfiguration`](https://www.adaptabletools.com/docs/reference/actioncolumndefaultconfiguration.md) Configuration properties to use for the default FDC3 Action Column. This is the Action Column that is rendered by AdapTable to display any provided FDC3 Buttons. It is of type [`ActionColumnDefaultConfiguration`](https://www.adaptabletools.com/docs/reference/actioncolumndefaultconfiguration.md) which is defined as follows: | Property | Type | Description | Default | | --- | --- | --- | --- | | [columnId](https://www.adaptabletools.com/docs/reference/actioncolumndefaultconfiguration.md#columnid) | `string` | Column Id | 'fdc3ActionColumn' | | [headerName](https://www.adaptabletools.com/docs/reference/actioncolumndefaultconfiguration.md#headername) | `string` | Column Header | 'FDC3 Actions' | | [movable](https://www.adaptabletools.com/docs/reference/actioncolumndefaultconfiguration.md#movable) | `boolean` | If Column is movable | false | | [resizable](https://www.adaptabletools.com/docs/reference/actioncolumndefaultconfiguration.md#resizable) | `boolean` | If Column is resizable | true | | [rowScope](https://www.adaptabletools.com/docs/reference/actioncolumndefaultconfiguration.md#rowscope) | [`RowScope`](https://www.adaptabletools.com/docs/reference/rowscope.md) | Which rows button appears in | data rows only | | [width](https://www.adaptabletools.com/docs/reference/actioncolumndefaultconfiguration.md#width) | `number` | Column Width in pixels | 200 | ```tsx {1} actionColumnDefaultConfiguration: { columnId: 'customFdc3MainActionColumn', width: 250, } ``` ### Full FDC3 Action Columns Instead of providing a set of FDC3 Buttons, developers can define a **full** FDC3 Action Column. - This allows for greater configurablity and flexibililty of the Action Column - It also allows for more than one Action Column to be visible in the Grid The Action Column is of type [`FDC3ActionColumn`](https://www.adaptabletools.com/docs/reference/fdc3actioncolumn.md) - a specialist, reduced form of the standard [Action Column](https://www.adaptabletools.com/docs/handbook-action-column/index.md) and contains these poperties: | Property | Type | Description | | --- | --- | --- | | [button](https://www.adaptabletools.com/docs/reference/fdc3actioncolumn.md#button) | [`Fdc3AdaptableButton`](https://www.adaptabletools.com/docs/reference/fdc3adaptablebutton.md) | FDC3 Button to display | | [columnId](https://www.adaptabletools.com/docs/reference/fdc3actioncolumn.md#columnid) | `string` | Id of the Column | | [defaultWidth](https://www.adaptabletools.com/docs/reference/fdc3actioncolumn.md#defaultwidth) | `number` | Default Width of column | | [friendlyName](https://www.adaptabletools.com/docs/reference/fdc3actioncolumn.md#friendlyname) | `string` | Column's friendly name | - Similar to FDC3 Buttons, AdapTable provides [default Icon and Tooltip values](#default-button-values) for FDC3 Action Column Buttons - These defaults themselves can be overridden by developers if required All defined Action Columns should be included in any relevant [Layouts definitions](https://www.adaptabletools.com/docs/handbook-layouts/index.md) ```tsx {6,7,8,9,10,11,12,13,22,23,24,25,26,27,28} fdc3Options: { intents: { raises: { ViewInstrument: [ { actionColumn: { columnId: 'fdc3ViewInstrumentColumn', friendlyName: 'FDC3: ViewInstrument', button: { id: 'ViewInstrumentButton', label: '_defaultFdc3', tooltip: '_defaultFdc3', icon: '_defaultFdc3', }, }, }, ], }, contexts: { broadcasts: { 'fdc3.currency': { actionColumn: { columnId: 'currency_column', friendlyName: 'Currency Column', button: { id: 'CurrencyButton', label: 'Announce Currency', icon: '_defaultFdc3', } }, }, }, }, }, ``` ## Default UI Property Values As a helpful aid to developers, AdapTable provides a special `_defaultFdc3` value. It is available when defining both FDC3 Ui Components - Context Menus and FDC3 Action Columns. When used, AdapTable will automatically supply the real values using sensible defaults The `_defaultFdc3` can be supplied for 2 properties (in both Context Menus and Action Columns): - `Icon` - AdapTable displays an appropriate Icon (for the Intent or the Context) - `Tooltip` - AdapTable renders relevant Tooltip text ### AdapTable Default Icons AdapTable provides a different default Icon to use for each Context and Intent. These are used by AdapTable when the `_defaultFdc3` value is given for an Icon property. ### List of Default Icons The default Icons used by AdapTable when the `_defaultFdc3` value is given are: **FDC3 Contexts** | FDC3 Context | Default Icon | Icon Name | | ---------------------------------------------------------------------------- | ---------------------------------------- | ------------ | | [Chart](https://fdc3.finos.org/docs/context/ref/Chart) | | pie-chart | | [ChatInitSettings](https://fdc3.finos.org/docs/context/ref/ChatInitSettings) | | chat | | [Contact](https://fdc3.finos.org/docs/context/ref/Contact) | | badge | | [ContactList](https://fdc3.finos.org/docs/context/ref/ContactList) | | badge | | [Country](https://fdc3.finos.org/docs/context/ref/Country) | | flag | | [Currency](https://fdc3.finos.org/docs/context/ref/Currency) | | dollar | | [Email](https://fdc3.finos.org/docs/context/ref/Chart) | | mail | | [Instrument](https://fdc3.finos.org/docs/context/ref/Instrument) | | money | | [InstrumentList](https://fdc3.finos.org/docs/context/ref/InstrumentList) | | money | | [Organization](https://fdc3.finos.org/docs/context/ref/Organization) | | organisation | | [Portfolio](https://fdc3.finos.org/docs/context/ref/Portfolio) | | building | | [Position](https://fdc3.finos.org/docs/context/ref/Position) | | building | | [TimeRange](https://fdc3.finos.org/docs/context/ref/TimeRange) | | date-range | | [Valuation](https://fdc3.finos.org/docs/context/ref/Valuation) | | equation | **FDC3 Intents** | FDC3 Intent | Default Icon | Icon Name | | ---------------------------------------------------------------------------- | ---------------------------------------- | ------------ | | [StartCall](https://fdc3.finos.org/docs/intents/ref/StartCall) | | call | | [StartChat](https://fdc3.finos.org/docs/intents/ref/StartChat) | | chat | | [StartEmail](https://fdc3.finos.org/docs/intents/ref/StartEmail) | | mail | | [ViewAnalysis](https://fdc3.finos.org/docs/intents/ref/ViewAnalysis) | | spark-line | | [ViewChart](https://fdc3.finos.org/docs/intents/ref/ViewChart) | | pie-chart | | [ViewContact](https://fdc3.finos.org/docs/intents/ref/ViewContact) | | person | | [ViewHoldings](https://fdc3.finos.org/docs/intents/ref/ViewHoldings) | | building | | [ViewInstrument](https://fdc3.finos.org/docs/intents/ref/ViewInstrument) | | money | | [ViewInteractions](https://fdc3.finos.org/docs/intents/ref/ViewInteractions) | | interactions | | [ViewNews](https://fdc3.finos.org/docs/intents/ref/ViewNews) | | news | | [ViewOrders](https://fdc3.finos.org/docs/intents/ref/ViewOrders) | | order | | [ViewProfile](https://fdc3.finos.org/docs/intents/ref/ViewProfile) | | badge | | [ViewQuote](https://fdc3.finos.org/docs/intents/ref/ViewQuote) | | quote | | [ViewResearch](https://fdc3.finos.org/docs/intents/ref/ViewResearch) | | science | ### User Default Icons If the AdapTable Default FDC3 Icons are not suitable, Developers can provide their own **Default Icons**. If provided, these developer-supplied icons will be used, in preference to the standard AdapTable defaults, whenever the `_defaultFdc3` value is given for an Icon property. The order of evaluation is: - no value provided - nothing is shown - `_defaultFdc3` (and no override) - AdapTable's default value is used - `_defaultFdc3` overridden - the default provided by the developer is used - property is explicitly set - this value is used --- # Filtering Grid Data Canonical page: https://www.adaptabletools.com/docs/handbook-filtering - AdapTable provides 2 forms of Filters - see the relevant page for details: - [Grid Filters](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) - [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) --- # Flashing Cells and Rows in AdapTable Canonical page: https://www.adaptabletools.com/docs/handbook-flashing-cell - AdapTable can be set up to flash Cells when the condition in a Rule is met - Flashing Rules can be created in the UI or defined in Initial Adaptable State - All Flashing-related properties (e.g. flashing styles, duration, target etc.) are highly configurable Flashing Cells in AdapTable allows users to see changes in cells values that matter to them. Cells or Rows can be made to flash on any change, or just when the change meets a defined rule. This rule can be provided to AdapTable at design-time or created at run-time. ## Flashing Concepts Flashing in AdapTable comprises 5 key concepts: - [Scope](#scope): **which** Columns or DataTypes when changed will cause the Flash to happen - [Rule](#rule): **why** the Flash is applied (i.e. what data change will cause a Cell or Row to flash) - [Styles](#change-styles): **how** the Flash is applied - different styles are available for up, down and neutral changes - [Duration](#duration): **when** (ie. how long) the Flash will be applied - either a number (of miliseconds) or 'always' - [Target](#target): **where** the Flash is applied - either the cell who's data changed, or the whole row You can set defaults for all these properties - so they are only overridden when they do not meet requirements **Example: Flashing Cells** Flashing Cells on Any Change - This very basic example sets all `numeric` column to flash (and has dummy data 'ticking' regularly) - The Rules uses the `ANY_CHANGE()` Expression Function so that all data changes will cause a Flash - The default settings for colours and durations are used ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Flashing Basic', initialState: { Dashboard: { ModuleButtons: ['FlashingCell'], }, Theme: {CurrentTheme: 'dark'}, 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', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; import {tickNumericData} from 'tickingDataHelper'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { tickNumericData(adaptableApi, 500, [ 'github_stars', 'github_watchers', 'open_issues_count', 'closed_issues_count', ]); }; ``` ### Scope Users can specify which columns or rows in AdapTable are able to flash. This is done by leveraging the commonly-used [Column Scope Object](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md). Scope contains up to 4 sets of options: - **Selected Columns** - a list of Columns which will Flash All Columns including [Calculated](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) and [FreeText](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) Columns can flash when changed - **Data Types** - All columns which have a particular data type (e.g. `number`, `text` or `date`) - **Column Types** - All columns which contain the selected [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) - **All Columns** - An entire Row can be Flashed by providing a Scope of 'All' Flashing Cells do **not** operate on [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) ### Rule The Rule determines whether a given data change should trigger a Flash. The Rule (similar to [Alert Rules](https://www.adaptabletools.com/docs/handbook-alerting/index.md) or [Column Formatting Conditions](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md)) can be one of 2 types : - [Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md): most common use case and ideal for straightforward changes - [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md): used for creating more complicated Rules and evaluated using [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) The most common Expression Function is `ANY_CHANGE` which returns true [for any data change](https://www.adaptabletools.com/docs/adaptable-ql-expression-relative-change/index.md#any_change) **Example: Flashing Cells using a Rule** Flashing Cells when change matches a Rule - In this example cells in 4 columns (`Github Stars`,` Github Watchers`, `Open Issues`, `Closed Issues`) tick regularly - However the Rule set is that they **only** flash when the ticking data change occurs in a row where the `Language` is 'JavaScript'. - Change the Rule so it flashes also (or instead) for TypeScript projects ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Cell Flashing Rule', initialState: { Dashboard: { ModuleButtons: ['FlashingCell'], }, Theme: {CurrentTheme: 'dark'}, FlashingCell: { FlashingCellDefinitions: [ { Name: 'flashingCell-language-JavaScript', Scope: { ColumnIds: [ 'github_stars', 'github_watchers', 'open_issues_count', 'closed_issues_count', ], }, Rule: { BooleanExpression: '[language] = "JavaScript"', }, }, ], }, 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, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; import {tickNumericData} from 'tickingDataHelper'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { tickNumericData(adaptableApi, 300, [ 'github_stars', 'github_watchers', 'open_issues_count', 'closed_issues_count', ]); }; ``` ### Change Styles There are 3 "Change Styles" for the Flash (which are all configurable): | Style | When Invoked | Column Data Types | | ----------- | ------------------------------- | ----------------- | | **Up** | Data change direction is `up` | number, date | | **Down** | Data change direction is `down` | number, date | | **Neutral** | Data change has no direction | text, boolean | ### Duration Duration sets for how long the cell / row will flash. The value provided can be one of 2 types: - a number (expressed in miliseconds) - 'always' - which will keep the cell / row in the new style indefinitely Use the `Clear Flash` [Context Menu Item](https://www.adaptabletools.com/docs/ui-context-menu/index.md) to remove a currently applied Flash Style from cells or rows ### Target Target defines what will Flash. There are 2 options: - **Cell** - the cell that triggered the data change - **Row** - the entire row which contains the cell which triggered the data change See [Flashing Rows](https://www.adaptabletools.com/docs/handbook-flashing-row/index.md) for more on using the `Row` Trigger ## Using Flashing Cells Run-time access to Cell Flashing is primarily available in the Flashing Cell section of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md). This displays a list of existing Flashing Cell Definitions with buttons to edit, suspend, share or delete. ### Using the Flashing Cell Wizard There are a few steps required when creating a Cell Flashing Rule: Provide a unique name for the Flashing Cell Definition. Specify **where** a data change can trigger Cell Flashing (if the Rule is met). Options are: - Any Column in the Row - One or more Columns - One or more Data Types - One or more Column Types (if provided) The [Column Scope Tutorial](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) provides more details on this topic Set the Adaptable Predicate that will Trigger the Flashing Cell. This can be either a System or Custom Predicate. The List of Predicates in the dropdown is filtered according to what was selected in the previous step. Some Predicates require one or more inputs which AdapTable will display if required. Use the Expression Editor to create a Boolean Expression. This can include as many functions, operators and references to other columns as required. Specify how long the Cell or Row should Flash for. You can provide: - a number (in milliseconds) - always - will keep the Cell / Row styled until you explicitly remove it (via Context Menu) You can provide up to 3 Styles: - Up Style - used in number and date columns - Down Style - used in number and date columns - Neutral Style - used in string and boolean For each Style you can set Fore, Back and Border colours together with font properties See [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) for more information on setting Styles ### Flashing Cell Menu Item Flashing can be turned **on** for any Column by clicking `Add Flashing Cell` in the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md). AdapTable can listen to 'neutral' data changes, so Flashing (and this menu item) is available in all columns This will create a new Flashing Cell Rule with 2 features: 1. An [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) using `ANY_CHANGE()` function so cells will flash when any data changes in the column 2. Using [Default Flashing properties](https://www.adaptabletools.com/docs/handbook-flashing-cell-configuring/index.md) that were set in Flashing Options (or provided by AdapTable) - Flashing can be turned **off** (for any Column which has a Flashing Scope of a single Column) - This is done via the `Remove Flashing Cell` menu item which appears automatically in the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md) ## Setting UI Entitlements The [UI Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) behaviour is as expected for `Full` and `Hidden` Access Levels. The `ReadOnly` Entitlement behaviour is that Flashing Cells will still be applied but Users are not permitted to manage or suspend them. --- # Configuring Cell Flashing Canonical page: https://www.adaptabletools.com/docs/handbook-flashing-cell-configuring - Developers are able to set default properties for Flashing Cells - These override the AdapTable defaults and are used when turning on Flashing from the Column Menu - These defaults can themselves, in turn, be overridden, when creating a Flashing Cell Definition Flashing, like everything in AdapTable, is highly configurable. ## Setting Flashing Defaults By default when Flashing is turned on for a column these values are used by AdapTable: -
Up Change Style
-
Down Change Style
-
Neutral Change Style
- Duration - 500ms - Flash Target - cell Like with any AdapTable object, different properties can be set for a particular Flashing Cell Definition - either at runtime in the Flashing Wizard or at design time in [Flashing Cell Initial State](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md). Those provided properties will then be used, in preference to the default values. However, it is additionally possible for developers to set their own default values for each of these properties. This is useful as it allows for Flashing to be turned on for a Column via the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md) These "new" defaults are supplied in the [Flashing Cell Options](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md) section of Adaptable Options. They will **only** be used if the equivalent property is not included in the Flashing Cell Definition (which takes priority) ### Rules of Precedence when using Flashing Cells This is the order of precedence AdapTable uses when deciding which property to use when Flashing a Cell: 1. Any property **explicitly set** in the Flashing Cell Definition - either provided at design-time or set in the UI 2. Any Default Value configured in [Flashing Cell Options](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md) 3. The AdapTable default value for that property ### Default Change Styles As noted, AdapTable provides 3 properties in [Flashing Cell Options](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md) which enable developers to set the Styles for flashing changes. All 3 properties are [Adaptable Styles](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) which is used in multiple Modules in AdapTable, and contains fore, back and border colours and a selection of font-related properties. - Unlike with other AdapTable Style use cases, you **cannot** provide [CSS ClassNames](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md#cssclass-option) for Flashing Cells - Instead only the provided properties of the Adaptable Style object can be used The default for these properties as set by AdapTable is to set just one property, `BackColor`, as follows: - `defaultUpChangeStyle` - Green - `defaultDownChangeStyle` - Red - `defaultNeutralChangeStyle` - Gray As the `Style` object can be used in Initial State (e.g for [Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md)>) the properties use pascal, not camel, casing ### `defaultUpChangeStyle` The default Style to Flash a Cell when it changes in an upward direction [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) Sets the default Style to use for Flashing Cells when the data change is 'up', where the current default (of `BackColur` of Green) is not desired. This only applies to Numeric or Date cells The property is an [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) - which is used in multiple places in AdapTable. ```ts {4} // Change the default Up Style const adaptableOptions: AdaptableOptions = { flashingCellOptions: { defaultUpChangeStyle: { BackColor: 'Brown', ForeColor: 'White', FontWeight: 'Bold', }, }, }; ``` ### `defaultDownChangeStyle` The default Style to Flash a Cell when it changes in a downward direction [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) Sets the default Style to use for Flashing Cells when the data change is 'down', where the current default (of `BackColur` of Red) is not desired. This only applies to Numeric or Date cells The property is an [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) - which is used in multiple places in AdapTable. ```ts {4} // Change the default Down Style const adaptableOptions: AdaptableOptions = { flashingCellOptions: { defaultDownChangeStyle: { BackColor: 'Brown', ForeColor: 'White', FontWeight: 'Bold', }, }, }; ``` ### `defaultNeutralChangeStyle` The default Style to Flash a Cell when it changes in a neutral direction [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) Sets the default Style to use for Flashing Cells when the data change is 'neutral', where the current default (of `BackColur` of Gray) is not desired. This generall applies to string cells where there is no obvious 'up' or 'down' direction The property is an [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) - which is used in multiple places in AdapTable. ```ts {4} // Change the default Neutral Style const adaptableOptions: AdaptableOptions = { flashingCellOptions: { defaultNeutralChangeStyle: { BackColor: 'Brown', ForeColor: 'White', FontWeight: 'Bold', }, }, }; ``` ### Default Flash Duration By default Cells (and Rows) will flash for half a second. This can be changed by using the `defaultFlashDuration` property in [Flashing Cell Options](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md). Either an alternative duration can be provided, or set to 'always' so the Style renders indefinitely. ### `defaultFlashDuration` Duration of Flashing Cell How long, by default, a Cell or Row will flash for. Possible values are: - any number (in milliseconds) - the default is 500 ```ts {4} // By default set Cells and Rows to flash for 1 second const adaptableOptions: AdaptableOptions = { flashingCellOptions: { defaultFlashDuration: 1000, }, }; ``` - `always` - the flash is never removed ```ts {4} // By default set Cells and Rows to flash indefinitely (or until removed by user) const adaptableOptions: AdaptableOptions = { flashingCellOptions: { defaultFlashDuration: 'always', }, }; ``` ### Default Flash Target By default the Target for all Flashes is the Cell that contains the changed value. The `defaultFlashTarget` property in [Flashing Cell Options](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md) allows the whole Row to flash by default. ### `defaultFlashTarget` Whether default behaviour is for a Cell or the whole Row to flash Sets the default target for Flashing Cells. This property is used if not overridden in a [Flashing Cell Definition](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md). Possible values are: - `cell` (the default) - `row` ```ts {4} // By default always Flash a Row (unless overridden in a Flashing Cell Definition) const adaptableOptions: AdaptableOptions = { flashingCellOptions: { defaultFlashTarget: 'row', }, }; ``` **Example: Changing Flashing Cell Defaults** Changing Flashing Colours and Duration - In this example we override some default Flashing Cell properties: - New (more pastel-based) default `up`, `down` and `neutral` change styles are provided - `duration` is increased to 1 second - These defaults are used by the `Github Stars` and `Github Watchers` Columns - However the `Open Issues` and `Closed Issues` Columns override these defaults - they provide: - bespoke styles of Blue (up change) and Brown (down change) - a Duration of 350ms ### See the Flashing Cell Definitions The Flashing Cell defaults are set in Flashing Cell Options: ```ts flashingCellOptions: { defaultDownChangeStyle: { BackColor: '#e18989', }, defaultUpChangeStyle: { BackColor: '#86d586', }, defaultNeutralChangeStyle: { BackColor: '#c67676', }, defaultFlashDuration: 1000 }, ``` These are overridden by the Flashing Cell Styles provided in Initial Adaptable State: ``` initialState: { FlashingCell: { FlashingCellDefinitions: [ { Name: 'Flashing_Cell_Github', Scope: { ColumnIds: ['github_stars', 'github_watchers'], }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, }, { Name: 'FlashingCell-2', Scope: { ColumnIds: ['open_issues_count', 'closed_issues_count'], }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, UpChangeStyle: { BackColor: 'Blue', ForeColor: 'White', }, DownChangeStyle: { BackColor: 'Brown', ForeColor: 'White', }, FlashDuration: 350 }, ], }, }, ``` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Flashing Options', flashingCellOptions: { defaultDownChangeStyle: { BackColor: '#e18989', }, defaultUpChangeStyle: { BackColor: '#86d586', }, defaultNeutralChangeStyle: { BackColor: '#c67676', }, defaultFlashDuration: 1000, }, initialState: { Dashboard: { ModuleButtons: ['FlashingCell'], }, Theme: {CurrentTheme: 'dark'}, FlashingCell: { FlashingCellDefinitions: [ { Name: 'flashingCell-github-anyChange', Scope: { ColumnIds: ['github_stars', 'github_watchers'], }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, }, { Name: 'flashingCell-Issues-anyChange', Scope: { ColumnIds: ['open_issues_count', 'closed_issues_count'], }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, UpChangeStyle: { BackColor: 'Blue', ForeColor: 'White', }, DownChangeStyle: { BackColor: 'Brown', ForeColor: 'White', }, FlashDuration: 350, }, ], }, 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, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; import {tickNumericData} from 'tickingDataHelper'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { tickNumericData(adaptableApi, 2000, [ 'github_stars', 'github_watchers', 'open_issues_count', 'closed_issues_count', ]); }; ``` ## Defining Flashing Cell Rules Cell Flashing rules can be defined at design-time via the [Flashing Cell](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md) section of Initial Adaptable State. This will ensure they are applied when the Application first loads and will be stored with Adaptable State. In addition default values can be set for the Styles used in Flashing. --- # Flashing Cell Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-flashing-cell-technical-reference - Flashing Cells can be defined in Initial Adaptable State and also configured in Adaptable Options - Run-time access is provided through Flashing Cell API - The Flashing Cell Displayed Event fires when a cell or row flashes ------------- ## Flashing Cell State The [`Flashing Cell`](https://www.adaptabletools.com/docs/reference/flashingcellstate.md) section of Initial State contains a collection of `FlashingCellDefinition` objects: | Property | Type | Description | | --- | --- | --- | | [FlashingCellDefinitions](https://www.adaptabletools.com/docs/reference/flashingcellstate.md#flashingcelldefinitions) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md)`[]` | Flashing Cell Definitions - will flash cells/rows when rule is met | ### Flashing Cell Definition Each [`Flashing Cell Definition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md) is defined as follows: | Property | Type | Description | Default | | --- | --- | --- | --- | | [DownChangeStyle](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md#downchangestyle) | [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) | Style for 'Down' value changes | Red BackColour | | [FlashDuration](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md#flashduration) | `number \| 'always'` | Duration of Flash - can be number (in ms) or 'always' | 500ms | | [FlashTarget](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md#flashtarget) | `FlashTargetTypes \| FlashTargetTypes[]` | Should a cell or whole row flash | 'cell' | | [Name](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md#name) | `string` | Name of the Flashing Cell Definition | | | [NeutralChangeStyle](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md#neutralchangestyle) | [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) | Style for 'Neutral' value changes | Gray BackColour | | [Rule](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md#rule) | `FlashingCellRule` | When Flashing Cell should be triggered | | | [Scope](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md#scope) | [`ColumnScope`](https://www.adaptabletools.com/docs/reference/columnscope.md) | Which Columns, DataTypes or Column Types can Flash | | | [UpChangeStyle](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md#upchangestyle) | [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) | Style for 'Up' value changes | Green BackColour | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | | [IsSuspended](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object | | ------------- ## Flashing Cell Options The [`Flashing Cell Options`](https://www.adaptabletools.com/docs/reference/flashingcelloptions.md) section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) contains Flashing Cell properties: | Property | Type | Description | Default | | --- | --- | --- | --- | | [defaultDownChangeStyle](https://www.adaptabletools.com/docs/reference/flashingcelloptions.md#defaultdownchangestyle) | [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) | Style for 'Down' value changes | Red BackColour | | [defaultFlashDuration](https://www.adaptabletools.com/docs/reference/flashingcelloptions.md#defaultflashduration) | `number \| 'always'` | Duration of Flash - can be number (in ms) or 'always' | 500ms | | [defaultFlashTarget](https://www.adaptabletools.com/docs/reference/flashingcelloptions.md#defaultflashtarget) | [`FlashTarget`](https://www.adaptabletools.com/docs/reference/flashtarget.md) | Should a cell or whole row flash | 'cell' | | [defaultNeutralChangeStyle](https://www.adaptabletools.com/docs/reference/flashingcelloptions.md#defaultneutralchangestyle) | [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) | Style for 'Neutral' value changes | Gray BackColour | | [defaultUpChangeStyle](https://www.adaptabletools.com/docs/reference/flashingcelloptions.md#defaultupchangestyle) | [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) | Style for 'Up' value changes | Green BackColour | --------- ## Flashing Cell API The [`Flashing Cell API`](https://www.adaptabletools.com/docs/reference/flashingcellapi.md) section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) contains numerous functions. They include functions to turn Cell Flashing off and on programmatically, and for Rules to be accessed, created, edited, deleted, suspended and shared. | Method | Returns | Description | | --- | --- | --- | | [addFlashingCellDefinition(flashingCellDefinition)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#addflashingcelldefinition) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md) | Adds a Flashing Cell Definition to State | | [addFlashingCellDefinitions(flashingCellDefinitions)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#addflashingcelldefinitions) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md)`[]` | Adds provided Flashing Cell Definitions | | [clearAllFlashingCells()](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#clearallflashingcells) | `void` | Clears all Cells and Rows which have been flashed (primarily used if duration is 'Always') | | [deleteFlashingCellDefinition(flashingCellDefinition)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#deleteflashingcelldefinition) | `void` | Deletes a Flashing Cell | | [editFlashingCellDefinition(flashingCellDefinition)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#editflashingcelldefinition) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md) | Edits Flashing Cell Definition in State with given one | | [editFlashingCellDefinitions(flashingCellDefinitions)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#editflashingcelldefinitions) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md)`[]` | Edits provided Flashing Cell Definitions | | [findFlashingCellDefinitions(flashingCellLookupCriteria)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#findflashingcelldefinitions) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md)`[]` | Find all Flashing Cell Definitions which match the given criteria | | [getActiveFlashingCellDefinitions(config)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#getactiveflashingcelldefinitions) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md)`[]` | Retrieves all active (non-suspended) cell Definitions in Flashing Cell State | | [getFlashingCellDefinitionById(id, config)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#getflashingcelldefinitionbyid) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md) | Retrieves Flashing Cell Definition by the technical ID (from `FlashingCellState`) | | [getFlashingCellDefinitionByName(name)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#getflashingcelldefinitionbyname) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md)` \| undefined` | Retrieves a Flashing Cell Definition by its Name | | [getFlashingCellDefinitions(config)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#getflashingcelldefinitions) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md)`[]` | Retrieves all Flashing Cell Definitions in Flashing Cell State | | [getFlashingCellFlashTarget(flashingCellDefinition)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#getflashingcellflashtarget) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md)`['FlashTarget']` | Returns `FlashTarget` of the given Flashing Cell Definition | | [getFlashingCellPredicateDefsForScope(scope)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#getflashingcellpredicatedefsforscope) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md)`[]` | Retrieves all Predicate Defs that match given Scope | | [getFlashingCellState()](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#getflashingcellstate) | [`FlashingCellState`](https://www.adaptabletools.com/docs/reference/flashingcellstate.md) | Retrieves Flashing Cell section from Adaptable State | | [getSuspendedFlashingCellDefinitions(config)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#getsuspendedflashingcelldefinitions) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md)`[]` | Retrieves all suspended Cell Definitions in Flashing Cell State | | [isAnyFlashingCellActive()](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#isanyflashingcellactive) | `boolean` | Is there any cells/rows currently being flashed | | [setFlashingCellDefinitions(flashingCellDefinitions)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#setflashingcelldefinitions) | `void` | Sets a collection of Flashing Cell Definitions into State | | [showFlashingCell(flashingCellToShow)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#showflashingcell) | `void` | Evaluates the given Flashing Cell Definition and flashes the correspondent cells/rows | | [suspendAllFlashingCellDefinition()](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#suspendallflashingcelldefinition) | `void` | Suspends all FlashingCell Definitions | | [suspendFlashingCellDefinition(flashingCellDefinition)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#suspendflashingcelldefinition) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md) | Suspends a Flashing Cell Definition | | [unSuspendAllFlashingCellDefinition()](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#unsuspendallflashingcelldefinition) | `void` | Activates all suspended Flashing Cell Definition | | [unSuspendFlashingCellDefinition(flashingCellDefinition)](https://www.adaptabletools.com/docs/reference/flashingcellapi.md#unsuspendflashingcelldefinition) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md) | Activates a suspended Flashing Cell Definition | ------------- ## Flashing Cell Displayed Event The `FlashingCellDisplayedEvent` fires when a Cell or Row has flashed. ### EventInfo The Flashing Cell Displayed Event has a [`FlashingCellDisplayedInfo`](https://www.adaptabletools.com/docs/reference/flashingcelldisplayedinfo.md) object which contains one property: | Property | Type | Description | | --- | --- | --- | | [flashingCell](https://www.adaptabletools.com/docs/reference/flashingcelldisplayedinfo.md#flashingcell) | [`AdaptableFlashingCell`](https://www.adaptabletools.com/docs/reference/adaptableflashingcell.md) | Details of the Cell (or row) which has just flashed | | [adaptableContext](https://www.adaptabletools.com/docs/reference/flashingcelldisplayedinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | This `flashingCell` property is of type [`AdaptableFlashingCell`](https://www.adaptabletools.com/docs/reference/adaptableflashingcell.md) defined as follows: | Property | Type | Description | | --- | --- | --- | | [cellDataChangedInfo](https://www.adaptabletools.com/docs/reference/adaptableflashingcell.md#celldatachangedinfo) | [`CellDataChangedInfo`](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md) | Data change which triggered the FlashingCell | | [direction](https://www.adaptabletools.com/docs/reference/adaptableflashingcell.md#direction) | `'up' \| 'down' \| 'neutral'` | Direction of the change: 'up', 'down' or 'neutral' | | [flashColumnIds](https://www.adaptabletools.com/docs/reference/adaptableflashingcell.md#flashcolumnids) | `Record` | Column Ids that are flashing | | [flashingCellDefinition](https://www.adaptabletools.com/docs/reference/adaptableflashingcell.md#flashingcelldefinition) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md) | Rule that caused the FlashingCell to fire | | [flashTarget](https://www.adaptabletools.com/docs/reference/adaptableflashingcell.md#flashtarget) | [`FlashingCellDefinition`](https://www.adaptabletools.com/docs/reference/flashingcelldefinition.md)`['FlashTarget']` | What will flash (e.g. Cell, Row) | | [rowPrimaryKey](https://www.adaptabletools.com/docs/reference/adaptableflashingcell.md#rowprimarykey) | `string` | Primary Key Value of Row which is flashing | ### Event Subscription Subscribing to the Events is done the same as with all [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md): ```ts api.eventApi.on('FlashingCellDisplayed', (eventInfo: FlashingCellDisplayedInfo) => { // do something with the info }); ``` --- # Flashing Rows Canonical page: https://www.adaptabletools.com/docs/handbook-flashing-row - Rows as well as Cells can be made to Flash due to a data change - This is often used with data that changes infrequently Most use cases of Flashing involve Cells which change colour briefly when their contents change. However whole Rows can be made to Flash in response to data changes. This is done by setting the target of the Flashing Cell Definition to `row` A common use case is when data changes infrequently and users want to see what has changed. In this scenario you can set the *Duration* to `always` so that the changed Row remains coloured until manually cleared **Example: Flashing Rows on Cell Change** Flashing a Whole Row when Cells Change - This example demonstrates how to flash a whole row - The `Github Stars` Column has been set up to 'tick' every 2 seconds - The Flashing Definition sets the **whole row** to flash when the Column ticks and to remain coloured **indefinitely** - Clear any coloured rows by selecting *Clear Flashing Cell for Row* from the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) - Or by clicking the *Clear All Flashing Rows* Custom Dashboard Button ```ts import { AdaptableButton, AdaptableOptions, DashboardButtonContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Flashing Row', dashboardOptions: { customDashboardButtons: [ { label: 'Clear All Flashing Rows', onClick: ( button: AdaptableButton, context: DashboardButtonContext ) => { context.adaptableApi.flashingCellApi.clearAllFlashingCells(); }, buttonStyle: { variant: 'raised', tone: 'neutral', }, }, ], }, initialState: { Dashboard: { ModuleButtons: ['FlashingCell'], }, Theme: {CurrentTheme: 'dark'}, FlashingCell: { FlashingCellDefinitions: [ { Name: 'flashingCell-language-TypeScript', Scope: { All: true, }, Rule: { BooleanExpression: '[language] = "TypeScript"', }, FlashTarget: 'row', FlashDuration: 'always', }, ], }, 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 {tickNumericData} from 'tickingDataHelper'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { tickNumericData(adaptableApi, 2000, ['github_stars']); }; ``` --- # Free Text Columns Canonical page: https://www.adaptabletools.com/docs/handbook-freetext-column - Free Text Columns allow run-time users to store custom data in AG Grid - Edits made in Free Text Columns are persisted in Adaptable State, rather than the Grid's Data Source - Each Free Text Column has a data type which can be Text, Numeric, Boolean or Date - It contains numerous other configurable properties e.g. width, filterable, groupable etc. - AdapTable will display a relevant cell editor when data is being added / edited in the Free Text Column Free Text Columns are 'special columns' where users can write - and save - bespoke data. This data is stored with the user's [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) and is **not persisted with the grid's data source**. The most common use case is to create 'Comment Columns' but any kind of bespoke data can be provided Free Text Columns - like [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-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. - Unlike [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md), Free Text Columns are always **editable** displaying a bespoke, rather than derived, value - Unlike [Styled Columns](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md), Free Text Column are special columns (and not specially rendered "normal" columns) Each Free Text Column can be given a data-type, an optional default value, and pre-populated if required. Free Text Columns 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: Free Text Columns** Using Free Text Columns in AdapTable - This example provides 3 Free Text Columns (defined in [Free Text Column Initial State](https://www.adaptabletools.com/docs/handbook-freetext-column-technical-reference/index.md)): 1. `Comments` - a **text** column: 3 Stored Values provided, and set to be *Resizable* 2. `Order Code` - a **number** column: default value of 123 and the Menu suppressed 3. `Is Used` - a **boolean** column: default value of `false` and 4 Stored Values provided of `true`, and set to be *Filterable* ### Expand to see the Free Text Column Definitions ```ts FreeTextColumn: { FreeTextColumns: [ { ColumnId: 'comments', FriendlyName: 'Comments', FreeTextStoredValues: [ {PrimaryKey: 24195339, FreeText: 'Used by US team'}, {PrimaryKey: 224663696, FreeText: 'My favourite'}, {PrimaryKey: 82095231, FreeText: 'Required by Support'}, ], FreeTextColumnSettings: { Resizable: true, DataType: 'text', }, }, { ColumnId: 'orderCode', FriendlyName: 'Order Code', DefaultValue: 123, FreeTextColumnSettings: { DataType: 'number', Sortable: false, SuppressMenu: true, }, }, { ColumnId: 'isUsed', FriendlyName: 'Is Used', DefaultValue: false, FreeTextStoredValues: [ {PrimaryKey: 10270250, FreeText: true}, {PrimaryKey: 24195339, FreeText: true}, {PrimaryKey: 224663696, FreeText: true}, {PrimaryKey: 82095231, FreeText: true}, ], FreeTextColumnSettings: { DataType: 'boolean', Filterable: true, Groupable: true, }, }, ], }, ``` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Free Text Column', initialState: { FreeTextColumn: { FreeTextColumns: [ { ColumnId: 'comments', FriendlyName: 'Comments', FreeTextStoredValues: [ {PrimaryKey: 24195339, FreeText: 'Used by US team'}, {PrimaryKey: 224663696, FreeText: 'My favourite'}, {PrimaryKey: 82095231, FreeText: 'Required by Support'}, ], FreeTextColumnSettings: { Resizable: true, DataType: 'text', }, }, { ColumnId: 'orderCode', FriendlyName: 'Order Code', DefaultValue: 123, FreeTextColumnSettings: { DataType: 'number', Sortable: false, SuppressMenu: true, }, }, { ColumnId: 'isUsed', FriendlyName: 'Is Used', DefaultValue: false, FreeTextStoredValues: [ {PrimaryKey: 10270250, FreeText: true}, {PrimaryKey: 24195339, FreeText: true}, {PrimaryKey: 224663696, FreeText: true}, {PrimaryKey: 82095231, FreeText: true}, ], FreeTextColumnSettings: { DataType: 'boolean', Filterable: true, Groupable: true, }, }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'comments', 'license', 'orderCode', 'language', 'isUsed', 'github_watchers', 'week_issue_change', '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, }, ], }, }, }; ``` ### How Free Text Columns Work in AdapTable Each time the application starts up AdapTable retrieves any Free Text Column definitions from AdapTable State. For each Free Text Column definition, AdapTable will then: 1. Create an Adaptable Column 2. Create an equivalent AG Grid column It is possible to define the Free Text Column in AG Grid Column Definitions and then to bind that AG Grid Column to the Free Text Column definition by using a [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) of `freeTextColumn` ## Free Text Column DataType All Free Text Columns have a **data type** which defines what type of data the column can store. - The `DataType` property in [`FreeTextColumn`](https://www.adaptabletools.com/docs/reference/freetextcolumn.md) can be set at run-time in the UI using the Free Text Column Wizard - Or provided at design time - it is the only mandatory property in `FreeTextColumnSettings` object There are 4 possible values for the Data Type: AdapTable displays an appropriate cell editor based on the Column's DataType - **text** (the default value) - shows a standard text editor - **number** - displays the AdapTable [Numeric Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-numeric/index.md) - **bBoolean** - displays a checkbox - **date** - displays the AdapTable [Date Picker](https://www.adaptabletools.com/docs/handbook-cell-editors-date-picker/index.md) If no value is set then the default value of text is used ## Default Value Free Text Columns can be a given a **default value**. This value be used automatically for every cell in the Column unless specifically overridden by the user. - The default value is NOT stored in the `FreeTextStoredValues` property, along with hand-edited values - However it is rendered in the cell each time it is displayed in the UI This option is available both when defining the column in [Free Text Column Initial Adaptable State](https://www.adaptabletools.com/docs/handbook-freetext-column-technical-reference/index.md) at design-time, and when creating it in the UI at run-time. Make sure to provide a default value which is consistent with the [DataType](#free-text-column-datatype) of the Column ## Default and Pre-Stored Values When defining Free Text Columns at design-time in [Initial Adaptable State](https://www.adaptabletools.com/docs/handbook-freetext-column-technical-reference/index.md), it is possible to provide some initial cell values, using the the `FreeTextStoredValues` property. These values will then display the first-time the Free Text Column is shown (and on all subsequent occasions unless they are overridden). - You cannot supply Free Text Stored Values when creating the Free Text Column in the UI - But you can, of course, provide them subsequently simply by editing the cells ## Formatted Free Text Columns Free Text Columns, once created, are like any other Column and can be treated as such. This means that they can be used with [Column Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) or as a [Styled Column](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md). **Example: Free Text Columns Formatting** Formatting Free Text Columns in AdapTable - This example provides 2 Free Text Columns which have been given additional formatting: 1. `Last Spoken` - a **date** column with 1 Stored Value (Note: a Date Picker appears when editing>) - we applied a [Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md) 2. `Status` - a **text** column with 5 Stored Values: we applied a [Badge Style](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md) and also limited the values that can be provided by using an [Select Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-select/index.md) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Free Text Column Formatted', editOptions: { showSelectCellEditor: context => { return context.column.columnId === 'status'; }, customEditColumnValues: context => { if (context.column.columnId === 'status') { return [ {label: 'Preferred', value: 'Preferred'}, {label: 'Allowed', value: 'Allowed'}, {label: 'On-boarding', value: 'On-boarding'}, {label: 'Not Allowed', value: 'Not Allowed'}, ]; } return context.defaultValues; }, }, initialState: { FreeTextColumn: { FreeTextColumns: [ { ColumnId: 'lastSpoken', FriendlyName: 'Last Spoken', FreeTextStoredValues: [ {PrimaryKey: 24195339, FreeText: new Date(2021, 5, 7)}, ], FreeTextColumnSettings: { DataType: 'date', }, }, { ColumnId: 'status', FriendlyName: 'Status', FreeTextColumnSettings: { DataType: 'text', }, FreeTextStoredValues: [ {PrimaryKey: 10270250, FreeText: 'Preferred'}, {PrimaryKey: 24195339, FreeText: 'Preferred'}, {PrimaryKey: 74293321, FreeText: 'Allowed'}, {PrimaryKey: 224663696, FreeText: 'On-boarding'}, {PrimaryKey: 76694515, FreeText: 'Not Allowed'}, ], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'license', 'lastSpoken', 'language', 'status', 'github_watchers', 'github_stars', 'week_issue_change', '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-lastSpoken', Scope: {ColumnIds: ['lastSpoken']}, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'yyyy/MM/dd', }, }, }, ], }, StyledColumn: { StyledColumns: [ { Name: 'status Badge', ColumnId: 'status', BadgeStyle: { Badges: [ { Predicate: { PredicateId: 'Is', Inputs: ['Preferred'], }, PillStyle: { BackColor: 'Green', ForeColor: 'White', }, }, { Predicate: { PredicateId: 'In', Inputs: ['Allowed', 'On-boarding'], }, PillStyle: { BackColor: 'Orange', ForeColor: 'White', }, }, { Predicate: { PredicateId: 'Is', Inputs: ['Not Allowed'], }, PillStyle: { BackColor: 'Red', ForeColor: 'White', }, }, ], }, }, ], }, }, }; ``` ## Using Free Text Columns Run-time access to Free Text Columns is available in the Free Text Column section of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md). There is no Free Text Column Toolbar or Tool Panel This displays a list of existing Free Text Columns with buttons to edit, share or delete each item. - Free Text Columns **cannot** be suspended - AdapTable will try to prevent you from deleting a Free Text Column which is referenced elsewhere There is also an Add button to create new Free Text Columns using the Free Text Column Wizard. - Newly created Free Text Columns are automatically added to the end of the Current [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) - Existing Free Text Columns include an `Edit Free Text Column` Menu Item in the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md) ### Using the Free Text Column Wizard There are 4 steps required when creating a Free Text Column: Provide an Id for the Free Text Column. This is the value used when referring to the Column in State or in other objects (e.g. Layouts). This is the value used to refer to the Column in the AdapTable UI. This defaults to the `ColumnId` value, so only provide the property if you need it to be different Choose what DataType you require for the Column. Options are: - Text (the default) - Number - Date - Boolean AdapTable provides an appropriate Cell Editor based on the Free Text Column's DataType. If the DataType is `Text`, then you can also choose which `TextEditor` to use; options are: - `Inline` - the default - `Large` - useful if providing large quantities of text Set a Default Value to be displayed in each cell unless explicitly overridden by the User. Choose which properties the Free Text Column should have (those set to true by default are marked with an asterix): - Filterable * - Resizable * - Groupable - Sortable * - Pivotable - Aggregatable - Suppress Menu - Suppress Movable - Editable * (cannot be unchecked) The new Free Text Column will be created and can be added by the user to 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. ## UI Entitlements The [UI Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) behaviour for Free Text Columns is as expected for `Full` and `Hidden` Access Levels. The `ReadOnly` Entitlement behaviour is that the Column will be displayed but Users are not permitted to edit or delete its configuration. If you are using an [auto-generated Primary Key](https://www.adaptabletools.com/docs/getting-started-primary-key/index.md#auto-generated-key) then Free Text Columns will **never** be available --- # Configuring Free Text Columns Canonical page: https://www.adaptabletools.com/docs/handbook-freetext-column-configuring - Free Text Columns can be defined at design-time using Free Text Column Initial State - The Free Text Column API can be used to add values programmatically at run-time ## Defining Free Text Columns Free Text Columns can be defined in [Free Text Column Initial Adaptable State](https://www.adaptabletools.com/docs/handbook-freetext-column-technical-reference/index.md). Each `FreeTextColumn` object contains 2 useful properties that can be provided if required: - `FreeTextStoredValues` - allows the Free Text Column to be 'pre-populated' with relevant data - `DefaultValue` - enables each cell to display a default value unless explicitly overridden by the User ### Defining a Free Text Column There are (up to) 6 properties that you need to provide: This value is used to refer to the Column in State This value is used to refer to the Column in AdapTable UI Whether the Column is `Text` `Number` `Date` or `Boolean` Is only mandatory property in `FreeTextColumnSettings` AdapTable provides an appropriate Cell Editor based on the DataType provided here Used in each cell unless explicitly overridden by the User Initial values to show in the column. Each is keyed against the Primary Key value for the Row. Provide additional settings for the Column (e.g. filterable, pivotable, resizable, sortable etc.) ```js [[1, 9, "ColumnId"],[2, 22, "FriendlyName"],[3, 16, "DataType"],[3, 25, "DataType"],[3, 34, "DataType"] ,[4, 23, "DefaultValue"],[5, 10, "FreeTextStoredValues"],[6, 17, "Aggregatable"],[6, 26, "Sortable"],[6, 35, "Filterable"]] // Provide 3 Free Text Columns // 1. Comments - string column with 3 initial values // 2. OrderCode - numeric column with default of 123 // 3. LastSpoken - a date Column const initialState: InitialState = { FreeTextColumn: { FreeTextColumns: [ { ColumnId: 'Comments', FreeTextStoredValues: [ { PrimaryKey: 12, FreeText: 'Dispatch asap' }, { PrimaryKey: 15, FreeText: 'Angry client' }, { PrimaryKey: 21, FreeText: 'Big order' }, ], FreeTextColumnSettings: { DataType: 'text', Aggregatable: false, }, }, { ColumnId: 'OrderCode', FriendlyName: 'Order Code', DefaultValue: 123, FreeTextColumnSettings: { DataType: 'number', Sortable: false, SuppressMenu: true, }, }, { ColumnId: 'LastSpoken', FriendlyName: 'Last Spoken', FreeTextColumnSettings: { DataType: 'date', Filterable: true, }, }, ], }, } ``` - To prevent filtering on Free Text Columns, set `enableFilterOnSpecialColumns` to *false* in [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) - This will also disallow filtering on **all** [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) and [Action Columns](https://www.adaptabletools.com/docs/handbook-action-column/index.md) ## Adding Values Programmatically A commonly used function in Free Text Column API is `setStoredValues` which allows you to update values stored in Free Text Columns programmatically. ### `setStoredValues` Adds Stored Values to a FreeText Column This is a useful function that allows you to add values to a FreeText Column programmatcally. The definition is: ```js setStoredValues( columnId: string, storedValues: FreeTextStoredValue[], replaceAction: 'All' | 'Conflicting' | 'None' ): void; ``` The `replaceAction` parameter defines the rules for how the new Stored Values should interact with any existing (and potentially clashing) cell values in the Column. The property can be one of 3 values with the following behaviour for each: - `All` - replaces **all** existing Stored Values for the Column with the new ones even if provided cells are currently empty - `Conflicting` - adds all given stored values and replaces any existing ones which clash with the new set - `None` - only adds the stored values where there are no existing entries with the same primary key ```ts // Replace all Existing Free Text Values in the Column with the 2 provided: const values: FreeTextStoredValue[] = [ { PrimaryKey: 5, FreeText: 'Fifth' }, { PrimaryKey: 6, FreeText: 'Sixth' } ]; api.freeTextColumnApi.setStoredValues('Comments', values, 'All'); ``` ## AG Grid Column Definitions Typically Free Text Columns are provided only in Initial Adaptable State and not also defined in Grid Options. However sometimes it is required to define the Free Text Column in AG Grid - e.g. if you want to show an AG Grid tooltip on the cell value. This is possible by specifying a [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) of `freeTextColumn` in the AG Grid Column Definition. Make sure `ColId` in the Column Definition and `ColumnId` in the Custom Column definition are the same value See [Adding Special Column Types](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) for more details and an accompanying demo --- # Free Text Column Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-freetext-column-technical-reference - The `FreeTextColumnAPI` provides run time access to the Free Text Column Module - It can be used to update Free Text Columns with new values programmatically --------- ## Free Text Column State The Free Text Column State contains a collection of `FreeTextColumn` objects: | Property | Type | Description | | --- | --- | --- | | [FreeTextColumns](https://www.adaptabletools.com/docs/reference/freetextcolumnstate.md#freetextcolumns) | [`FreeTextColumn`](https://www.adaptabletools.com/docs/reference/freetextcolumn.md)`[]` | Collection of Free Text Columns | ### Free Text Column A [`FreeTextColumn`](https://www.adaptabletools.com/docs/reference/freetextcolumn.md) FreeTextColumn object is defined as follows: | Property | Type | Description | Default | | --- | --- | --- | --- | | [ColumnId](https://www.adaptabletools.com/docs/reference/freetextcolumn.md#columnid) | `string` | Id of Column | | | [DefaultValue](https://www.adaptabletools.com/docs/reference/freetextcolumn.md#defaultvalue) | `any` | Initial value to use for each cell in the Column | | | [FreeTextColumnSettings](https://www.adaptabletools.com/docs/reference/freetextcolumn.md#freetextcolumnsettings) | [`FreeTextColumnSettings`](https://www.adaptabletools.com/docs/reference/freetextcolumnsettings.md) | Additional optional properties for Column (e.g. filterable, resizable) | | | [FreeTextStoredValues](https://www.adaptabletools.com/docs/reference/freetextcolumn.md#freetextstoredvalues) | [`FreeTextStoredValue`](https://www.adaptabletools.com/docs/reference/freetextstoredvalue.md)`[]` | Collection of Stored Values to aplly in the Column | | | [FriendlyName](https://www.adaptabletools.com/docs/reference/freetextcolumn.md#friendlyname) | `string` | Friendly Name to use to refer to Column; if unset `ColumnId` is used | | | [TextEditor](https://www.adaptabletools.com/docs/reference/freetextcolumn.md#texteditor) | `'Inline' \| 'Large'` | Cell editor to use when editing a string Free Text Column | 'Inline' | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/freetextcolumn.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | ### Free Text Stored Value The `FreeTextColumn` object includes an array of [`FreeTextStoredValue`](https://www.adaptabletools.com/docs/reference/freetextstoredvalue.md) defined as follows: | Property | Type | Description | | --- | --- | --- | | [FreeText](https://www.adaptabletools.com/docs/reference/freetextstoredvalue.md#freetext) | `any` | Value to store in the cell | | [PrimaryKey](https://www.adaptabletools.com/docs/reference/freetextstoredvalue.md#primarykey) | `any` | Primary Key Column value for the row | Free Text Stored Values will typically be added by users at run-time, rather than set at design-time ### Free Text Column Settings The `freeTextColumnSettings` property is of type [`FreeTextColumnSettings`](https://www.adaptabletools.com/docs/reference/freetextcolumnsettings.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 | | --------- ## Free Text Column API Full programmatic access to Free Text Columns is available in Free Text Column API. This enables Free Text Columns to be created, edited, cloned, deleted and shared programmatically. | Method | Returns | Description | | --- | --- | --- | | [addFreeTextColumn(freeTextColumn)](https://www.adaptabletools.com/docs/reference/freetextcolumnapi.md#addfreetextcolumn) | [`FreeTextColumn`](https://www.adaptabletools.com/docs/reference/freetextcolumn.md) | Adds new FreeTextColumn to Adaptable State | | [deleteFreeTextColumn(columnId)](https://www.adaptabletools.com/docs/reference/freetextcolumnapi.md#deletefreetextcolumn) | `void` | Deletes FreeTextColumn with given ColumnId from Adaptable State | | [editFreeTextColumn(freeTextColumn)](https://www.adaptabletools.com/docs/reference/freetextcolumnapi.md#editfreetextcolumn) | [`FreeTextColumn`](https://www.adaptabletools.com/docs/reference/freetextcolumn.md) | Edits existing FreeTextColumn in Adaptable State | | [getFreeTextColumnById(id)](https://www.adaptabletools.com/docs/reference/freetextcolumnapi.md#getfreetextcolumnbyid) | [`FreeTextColumn`](https://www.adaptabletools.com/docs/reference/freetextcolumn.md)` \| undefined` | Retrieves FreeTextColumn by the technical ID (from `FreeTextColumnState`) | | [getFreeTextColumnForColumnId(columnId)](https://www.adaptabletools.com/docs/reference/freetextcolumnapi.md#getfreetextcolumnforcolumnid) | [`FreeTextColumn`](https://www.adaptabletools.com/docs/reference/freetextcolumn.md)` \| undefined` | Gets FreeText Column, if any, for given ColumnId | | [getFreeTextColumns()](https://www.adaptabletools.com/docs/reference/freetextcolumnapi.md#getfreetextcolumns) | [`FreeTextColumn`](https://www.adaptabletools.com/docs/reference/freetextcolumn.md)`[]` | Gets all FreeTextColumns in Adaptable State | | [getFreeTextColumnState()](https://www.adaptabletools.com/docs/reference/freetextcolumnapi.md#getfreetextcolumnstate) | [`FreeTextColumnState`](https://www.adaptabletools.com/docs/reference/freetextcolumnstate.md) | Retrieves FreeTextColumn section of Adaptable State | | [getFreeTextColumnValueForRowNode(freeTextColumn, rowNode)](https://www.adaptabletools.com/docs/reference/freetextcolumnapi.md#getfreetextcolumnvalueforrownode) | `any` | Retrieves a Free Text Column value for a given row node | | [openFreeTextColumnSettingsPanel()](https://www.adaptabletools.com/docs/reference/freetextcolumnapi.md#openfreetextcolumnsettingspanel) | `void` | Opens Settings Panel with Free Text Column section selected and visible | | [setStoredValue(columnId, storedValue)](https://www.adaptabletools.com/docs/reference/freetextcolumnapi.md#setstoredvalue) | [`FreeTextColumn`](https://www.adaptabletools.com/docs/reference/freetextcolumn.md) | Sets FreeTextStoredValue for the FreeTextColumn with the given ColumnId (replaces existing one if exists) | | [setStoredValues(columnId, storedValues, replaceAction)](https://www.adaptabletools.com/docs/reference/freetextcolumnapi.md#setstoredvalues) | `void` | Sets Stored Values to the FreeTextColumn with the given ColumnId | --- # AdapTable Grid Filter Canonical page: https://www.adaptabletools.com/docs/handbook-grid-filter - AdapTable provides Grid Filters which will search AG Grid's data source and display only matching rows - It is a property of a [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) and complements (and can be used together with) [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) - Grid Filters wrap [Boolean Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) which are evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) - Boolean Expressions can contain multiple conditions and operators and reference numerous columns - Grid Filters can be named and saved as Named Queries and then re-run as often as required The AdapTable Grid Filter allows users to run complex, multi-condition searches across multiple Columns. These will then be evaluated across the whole of AG Grid's data source. - Grid Filters complement, and are designed to work in conjunction, with [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) - Both Grid and Column Filters can be active at the same time AdapTable will display **only** those rows that match **all** the Conditions in the Grid Filter. Grid Filters differ from [Quick Search](https://www.adaptabletools.com/docs/handbook-quick-search/index.md) in that they display matching rows, rather than higlight matching cells The Grid Filter is saved (and can be defined) in the Current [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md). There can only be **one** active Grid Filter at any time ## Boolean Expressions Grid Filters are essentially wrappers around [Boolean Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) - powerful, configurable, querying constructs that can contain multiple conditions and operators and will return a **boolean** (true/false) result. Some Expressions (e.g. those used by [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md)) can have any return type, but a Grid Filter Expression must always return a Boolean value As with all Expressions, Grid Filters are evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) - AdapTable's native Query Language. Grid Filters can be hand written directly in the [Grid Filter Toolbar](https://www.adaptabletools.com/docs/ui-dashboard/index.md#tabs-and-toolbars) but AdapTable provides two UI components to facilitate the creation of Boolean Expressions: - a [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md) for standard Expressions - an [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) for more complex requirements **Example: Applying a Grid Filter** Using AdapTableQL to run Grid Filter - This example runs a Grid Filter which returns the most popular JavaScript packages - The Expression is `[language]="JavaScript" AND ([github_watchers] > 2000 OR [github_stars] > 14500)` - The Grid Filter Toolbar has been [Pinned](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md#pinned-toolbars) so it sits above the Grid - See how the Grid Filter updates by editing the Expression directly in the Grid Filter Toolbar - Alternatively, click the Expand button (which shows 2 arrows) on the left of the Toolbar to open the [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md) and [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Basic Grid Filter', initialState: { Dashboard: { PinnedToolbars: ['GridFilter'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['GridFilter'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'language', 'github_stars', 'github_watchers', 'has_wiki', 'updated_at', 'license', 'created_at', 'topics', 'pushed_at', 'description', 'open_issues_count', ], GridFilter: { Expression: '[language]="JavaScript" AND ([github_watchers] > 2000 OR [github_stars] > 14500)', }, AutoSizeColumns: true, }, ], }, }, }; ``` ## Named Queries Grid Filters are typically created on the fly, evaluated immediatedly, and then cleared when no longer needed. However, if required, Grid Filter Expressions can be named and saved in order to be re-used at a later date. In this scenario it is called a **Named Query** and persisted into Named Query State. It will then be available for loading at a later point in time (in this or future sessions). See [Named Queries](https://www.adaptabletools.com/docs/handbook-named-queries/index.md) for full details on this topic ## Comparing Columns One advantage of the Grid Filter over [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) is that it can be used to compare values in 2 Columns. This can be done in both the Query Builder and the Expression Editor. Only rows which pass **both** sets of evaluation will be displayed **Example: Comparing Column values with the Grid Filter** Using Grid Filter to compare values in 2 Columns - This example runs a Grid Filter which compares 2 sets of columns - The Expression is: `[closed_issues_count] > [closed_pr_count] AND [pushed_at] = [updated_at]` - Open the Grid Filter in the Expression Editor or Query Builder to see how the Columns are compared ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Grid Filter - Column Comparison', initialState: { Dashboard: { PinnedToolbars: ['GridFilter'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['GridFilter'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'language', 'github_stars', 'github_watchers', 'has_wiki', 'updated_at', 'license', 'created_at', 'topics', 'pushed_at', 'description', 'open_issues_count', ], GridFilter: { Expression: '[closed_issues_count] > [closed_pr_count] AND [pushed_at] =[updated_at] ', }, AutoSizeColumns: true, }, ], }, }, }; ``` ## Grid Filter with Column Filters The Grid Filter can be applied simultaneously with any [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md). Only rows which pass **both** sets of evaluation will be displayed in the Grid **Example: Grid Filter and Column Filters** Applying a Grid Filter with Column Filters - This example runs a Grid Filter as well as 4 Column Filters - Only the 3 rows which pass **both** sets of evaluations are displayed ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Grid Filter with Column Filters', initialState: { Dashboard: { PinnedToolbars: ['GridFilter'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['GridFilter'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'language', 'github_stars', 'github_watchers', 'license', 'pushed_at', 'updated_at', 'has_wiki', 'created_at', 'description', 'open_issues_count', 'topics', ], GridFilter: { Expression: '[license]="MIT License" OR [github_watchers] > 2000', }, ColumnFilters: [ { ColumnId: 'language', Predicates: [ { PredicateId: 'In', Inputs: ['TypeScript', 'JavaScript'], }, ], }, { ColumnId: 'github_stars', Predicates: [ { PredicateId: 'Between', Inputs: ['5000', '90000'], }, ], }, { ColumnId: 'name', Predicates: [ { PredicateId: 'EndsWith', Inputs: ['.js'], }, ], }, { ColumnId: 'pushed_at', Predicates: [ { PredicateId: 'After', Inputs: ['2016-01-01'], }, ], }, ], AutoSizeColumns: true, }, ], }, }, }; ``` ## Managing the Grid Filter The Grid Filter is accessible to both design-time and run-time users as follows: - Developers can **define** a GridFilter (using the `GridFilter` property inthe [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) Definition) - Developers can **configure** the GridFilter to match custom requirements - Run-time users can **use** (ie. set, edit, clear, save, reload etc) the Grid Filter See [Defining the Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter-defining/index.md) or [Configuring the Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter-configuring/index.md) or [Using the Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter-using/index.md) for more information ## UI Entitlements The [UI Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) behaviour for Grid Filter is as follows: - `Full` - Grid Filters can be run fully and the UI components are available and display normally - `Hidden` - No Grid Filter UI components are visible or available - `ReadOnly` - Grid Filters can be created and run, but they cannot be saved as Named Queries --- # Configuring the Grid Filter Canonical page: https://www.adaptabletools.com/docs/handbook-grid-filter-configuring - Developers can choose which of the Grid Filter UI controls (Query Builder or Expression Editor) are available - Run-time users can create and manage the Grid Filter in multiple ways ## Setting UI Controls By default both the [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md) and [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) are available to create a Grid Filter. However developers can configure AdapTable so that only one of these UI components is available. This is done using the `availableFilterEditors` property in the [Grid Filter Options](https://www.adaptabletools.com/docs/handbook-grid-filter-technical-reference/index.md) section of Filter Options. ### `availableFilterEditors` Which Editors are available for users to create Grid Filters Set which of the UI Components should be available to end users when they create / edit Grid Filters. ```ts {3} // Only make the Query Builder available gridFilterOptions: { availableFilterEditors: ['QueryBuilder'] }, ``` This is useful when you prefer that users only use Query Builder and not the complexity of the Expression Editor **Example: Grid Filter with Query Builder only** Grid Filter: Setting which UI Components are available - This demo sets only the Query Builder to be used to create a Grid Filter (and not the Expression Editor also) - Click the "Expand" button in the Grid Filter toolbar and note that only the Query Builder is available ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Query Builder only', // TODO: re-enable once documentation depends on an AdapTable release that includes // expressionOptions.editorOptions (available on `dev`, not yet in 23.0.14). // expressionOptions: { // editorOptions: { // availableEditors: ['QueryBuilder'], // }, // }, initialState: { Dashboard: { PinnedToolbars: ['GridFilter'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['GridFilter'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'language', 'github_stars', 'github_watchers', 'has_wiki', 'updated_at', 'license', 'created_at', 'topics', 'pushed_at', 'description', 'open_issues_count', ], GridFilter: { Expression: '[language]="JavaScript" AND ([github_watchers] > 2000 OR [github_stars] > 14500)', }, AutoSizeColumns: true, }, ], }, }, }; ``` ## Clearing Grid Filter on Startup AdapTable always saves the previously applied Grid Filter into AdapTable State (via the Current Layout). It will then automatically re-apply this Grid Filter 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 the Grid Filter (and any Column 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 the Grid Filter. It then re-applies the persisted Grid Filter when the application re-starts. Setting this property to *true* will remove the Grid Filter (and any Column Filters) in Adaptable State from the previous session, and display a non-filtered AG Grid instance. ```ts {4} // Clear any previously set Grid or Column 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) --- # Defining the Grid Filter Canonical page: https://www.adaptabletools.com/docs/handbook-grid-filter-defining - The Grid Filter is defined in a Layout - either Table or Pivot The Grid Filter in AdapTable is defined inside the Layout object This means that the Grid Filter is per-Layout only The Grid Filter can be defined for both Table and Pivot Layouts. ### Adding Grid Filter to Layout Add the `GridFilter` prop to the Layout in order to filter across the whole Grid. Add it separately to each Layout where you want to apply it. The Grid Filter can be defined for both Table and Pivot Layouts. The Grid Filter contains an `Expression` property. This is a simple [(Boolean) Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) that is evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md). ```js [[1, 9, "GridFilter"],[1, 18, "GridFilter"],[2, 10, "Expression"],[2, 19, "Expression"]] const adaptableOptions: AdaptableOptions = { const initialState: InitialState = { Layout: { CurrentLayout: 'Table Layout', Layouts: [ { Name: 'Table Layout', TableColumns: ['currency', 'orderData', 'github_watchers', 'price'], GridFilter: { Expression: '[currency]="EUR" OR [price] > 5000)', }, }, { Name: 'Pivot Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license'], PivotAggregationColumns: [ { ColumnId: 'price', AggFunc: 'sum' } ], GridFilter: { Expression: '[currency]="EUR" OR [price] > 5000)', }, }, ] } ``` --- # Grid Filter Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-grid-filter-technical-reference - The Current GridFilter is stored in the Layout - Grid Filters are configured in Grid Filter Options and available at runtime through the Grid Filter API - The Grid Filter Applied Event fires when the Grid Filter is set ## Grid Filter State There is no Grid Filter State. Instead the Grid Filter is defined as a property of a [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) in [Layout Initial State](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md). ---- ## Grid Filter Options The properties in Grid Filter Options are used to configure the Grid Filter: | Property | Type | Description | Default | | --- | --- | --- | --- | | [availableFilterEditors](https://www.adaptabletools.com/docs/reference/gridfilteroptions.md#availablefiltereditors) | [`GridFilterEditors`](https://www.adaptabletools.com/docs/reference/gridfiltereditors.md) | Which UI Components can be used to edit a Grid Filter: Expression Editor, Query Builder (or both) | ['ExpressionEditor', 'QueryBuilder'] | ---- ## Grid Filter API | Method | Returns | Description | | --- | --- | --- | | [clearGridFilter()](https://www.adaptabletools.com/docs/reference/gridfilterapi.md#cleargridfilter) | `void` | Clears the Grid Filter (for the current Layout) | | [getCurrentGridFilter()](https://www.adaptabletools.com/docs/reference/gridfilterapi.md#getcurrentgridfilter) | [`GridFilter`](https://www.adaptabletools.com/docs/reference/gridfilter.md)` \| undefined` | Retrieves the Grid Filter from the current Layout | | [getCurrentGridFilterExpression()](https://www.adaptabletools.com/docs/reference/gridfilterapi.md#getcurrentgridfilterexpression) | `string \| undefined` | Retrieves the Grid Filter's Expression from the current layout | | [openUIEditorForGridFilter(expression)](https://www.adaptabletools.com/docs/reference/gridfilterapi.md#openuieditorforgridfilter) | `void` | Opens the AdapTableQL UI Components (Expression Editor & Query Builder) | | [reApplyGridFilter()](https://www.adaptabletools.com/docs/reference/gridfilterapi.md#reapplygridfilter) | `void` | Re-applies the Grid Filter | | [setGridFilterExpression(expression)](https://www.adaptabletools.com/docs/reference/gridfilterapi.md#setgridfilterexpression) | `void` | Sets the Grid Filter (for the current layout) | | [setGridFilterExpressionUsingNamedQuery(namedQuery)](https://www.adaptabletools.com/docs/reference/gridfilterapi.md#setgridfilterexpressionusingnamedquery) | `void` | Sets the Grid Filter (for the current layout) | | [suspendGridFilter()](https://www.adaptabletools.com/docs/reference/gridfilterapi.md#suspendgridfilter) | `void` | Suspends the Grid Filter | | [unSuspendGridFilter()](https://www.adaptabletools.com/docs/reference/gridfilterapi.md#unsuspendgridfilter) | `void` | Unsuspends the Grid Filter | ---- ## Grid Filter Applied Event The Grid Filter Applied Event is triggered whenever a [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) is applied in AdapTable. This is often used when wanting to [manage expressions on the Server](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md) ### GridFilterAppliedInfo The Grid Filter Applied Event has a [`GridFilterAppliedInfo`](https://www.adaptabletools.com/docs/reference/gridfilterappliedinfo.md) object defined as follows: | Property | Type | Description | | --- | --- | --- | | [gridFilter](https://www.adaptabletools.com/docs/reference/gridfilterappliedinfo.md#gridfilter) | [`GridFilter`](https://www.adaptabletools.com/docs/reference/gridfilter.md)` \| undefined` | Current Grid Filter | | [gridFilterExpressionAST](https://www.adaptabletools.com/docs/reference/gridfilterappliedinfo.md#gridfilterexpressionast) | `any` | AST for Current Grid Filter Expression | | [adaptableContext](https://www.adaptabletools.com/docs/reference/gridfilterappliedinfo.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('GridFilterApplied', (eventInfo: GridFilterAppliedInfo) => { // do something with the info }); ``` --- # Using the Grid Filter Canonical page: https://www.adaptabletools.com/docs/handbook-grid-filter-using - Run-time users can create and manage the Grid Filter in multiple ways Run-time users (if correctly [permissioned](https://www.adaptabletools.com/docs/handbook-permissioning/index.md)) can write, edit, delete, clear, save and reload Grid Filter Expressions. ## Writing Grid Filters AdapTable users can write Grid Filter Expressions by hand which will be evaluated immediately by AdapTable. Grid Filter Expressions can be written directly in the Grid Filter [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard/index.md#tabs-and-toolbars) or [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) and they will be applied and evaluated when the Run button is clicked. But, more often, users will click the Expand button to open the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) or [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md) which provide a richer environment for writing Expressions. The Expression UI Components include functions lists, intuitive UI controls and context sensitive help Users can create multiple Grid Filters and load them on demand, but **only one** Grid Filter can be run (and active) at any one time. ## Editing Grid Filters A Grid Filter can be easily be edited in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) or [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md) and then re-run. Editing a Named Query creates a new Grid Filter - which can then itself be saved as a new Named Query ## Validating Grid Filters [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) automatically validates the Grid Filter as it is being written. AdapTable will only enable the Run button if the Grid Filter's Expression is valid Set `performExpressionValidation` in [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md) to false to turn off automatic validation. This is useful if you are [evaluating the Grid Filter on your server](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md) ## Clearing Grid Filters The Grid Filter can be cleared by clicking the *Clear Grid Filter* button in the Grid Filter Toolbar or Tool Panel. This will have the effect of showing all rows in the Grid (subject to any [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) that have been applied). - Cleared Queries can be subsequently [reloaded](#loading-queries) - This applies both to [Named Queries](https://www.adaptabletools.com/docs/handbook-named-queries/index.md) or unsaved Grid Filters (but only those created in the current session). ## Saving Grid Filters A Grid Filter can be saved by clicking the *Save* button in the Grid Filter Toolbar or Tool Panel. This will save the Grid Filter as a [Named Query](https://www.adaptabletools.com/docs/handbook-named-queries/index.md) for re-use as required. Grid Filters which are not saved explicity are still persisted temporarily and can be reloaded during the current session ## Loading Grid Filters The Grid Filter [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard/index.md#tabs-and-toolbars) and [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) both contain a dropdown which allow for previously run Expressions to be loaded and then run as a Grid Filter. The dropdown includes all saved [Named Queries](https://www.adaptabletools.com/docs/handbook-named-queries/index.md), plus any unsaved Grid Filters created in the Current Session. Unsaved Grid Filters are named according to the time of creation (e.g. 'Grid Filter at 5:38:33 PM') --- # Column Grouping Canonical page: https://www.adaptabletools.com/docs/handbook-grouping-columns - Column Groups are fully supported in AdapTable - The Layout Wizard provides details of Column Groups and respects any Column Grouping rules AdapTable fully supports [AG Grid Column Grouping](https://www.ag-grid.com/javascript-data-grid/column-groups/) (sometimes known as column banding). This is where multiple columns are placed in one group and given an additional, common Header. **Example: Column Groups** Using Column Grouping in AdapTable - 3 Column Groups have been defined in `colDefs` in Grid Options: - `Issues & PRs` - contains `Open PRs`, `Closed PRs`, `Open Issues` and `Closed Issues` Columns - has `marryChildren` set to *true* - so columns **cannot** be out of the Group - `Open Issues` and `Closed Issues` Columns set with `columnGroupShow` as 'closed' - `Dates` - contains 3 Date Columns: `Updated`, `Pushed`, `Created` - has `marryChildren` set to *false* - so columns **can** be out of the Group - `Details` - contains `Description`, `License`, `Has Wiki`, `Has Projects` & `Has Pages` Columns - has `marryChildren` set to *true* - so columns **cannot** be out of the Group - the `Description` column has `columnGroupShow` set to 'closed' ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Column Grouping', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'description', '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, ColGroupDef} from 'ag-grid-enterprise'; export const columnDefs: (ColDef | ColGroupDef)[] = [ { field: 'id', cellDataType: 'number', hide: true, editable: false, }, { field: 'name', cellDataType: 'text', }, { headerName: 'Issues & PRs', marryChildren: true, children: [ { 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: 'language', cellDataType: 'text', enablePivot: true, enableRowGroup: true, }, { headerName: 'Dates', marryChildren: false, children: [ { field: 'created_at', headerName: 'Created', cellDataType: 'date', }, { field: 'updated_at', headerName: 'Updated', cellDataType: 'date', }, { field: 'pushed_at', headerName: 'Pushed', cellDataType: 'date', }, ], }, { headerName: 'Details', marryChildren: true, children: [ { field: 'description', cellDataType: 'text', sortable: false, 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: 'github_stars', headerName: 'GitHub Stars', cellDataType: 'number', enableValue: true, }, { field: 'github_watchers', headerName: 'GitHub Watchers', cellDataType: 'number', enableValue: true, }, { field: 'week_issue_change', headerName: 'Issue Change', cellDataType: 'number', enableValue: true, }, ]; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; import {tickNumericData} from 'tickingDataHelper'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { tickNumericData(adaptableApi, 200, [ 'github_stars', 'github_watchers', 'open_issues_count', 'closed_issues_count', 'open_prs_count', 'closed_prs_count', ]); }; ``` ## Layouts Column Groups are not specified in [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) - as the GridOptions definition is sufficient. But they are **respected** in Layouts. For instance, in the Column list the Layout Editor displays the name of any Column Group a column belongs to. It also prevents users moving columns out of Column Groups, where this is not allowed in the AG Grid definition. ## Column Names By default AdapTable will not change the `FriendlyName` of a Column when it is in a Column Group. The Friendly Name is how AdapTable refers to the Column e.g. in Wizards or Expression Editor However sometimes the same Friendly Name can appear in multiple Column Groups (e.g. 3 columns groups each have a `Bid` and `Ask` column). When this is the case, there are 2 ways to make the FriendlyName unique: ### Adding Column Group Name The simplest way to ensure uniqueness of FriendlyName for Columns in Column Groups is via the `addColumnGroupToColumnFriendlyName` property in [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md). This will append the name of the Column Group to the Friendly Name (e.g. "Bid [Bbg]", "Bid[Markit]"). ### Using a property Use the `columnFriendlyName` property also in [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md). See the [Developer Tutorial on Configuring Column Headers](https://www.adaptabletools.com/docs/dev-guide-columns-column-headers/index.md) for more details ## Special Columns AdapTable provides 3 "Special Columns" which are created dynamically. - [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - [Action Column](https://www.adaptabletools.com/docs/handbook-action-column/index.md) - [FreeText Column](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) These can also be included in Column Groups, by providing these 2 steps: - Add them explicitly in AG Grid Columns Defs (this is not normally required for Special Columns) - Provide them with a [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) of `calculatedColumn`, `freeTextColumn` or `actionColumn` **Example: Column Groups with Special Columns** Column Groups containing Calculated, FreeText or Action Columns - This example contains a Column Group (called 'Special Columns') which includes 3 Special Columns: - `Big Stars` - a [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - `Add Issue` - an [Action Column](https://www.adaptabletools.com/docs/handbook-action-column/index.md) - `Comments` - a [FreeText Column](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) - All 3 columns were defined in Column Defs (as well as Adaptable Options / Initial Adaptable State) - And all 3 columns were given a matching [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) to wire it all up together ```ts import { ActionColumnButton, ActionColumnContext, AdaptableButton, AdaptableOptions, CellUpdateRequest, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Column Grouping with Special Columns', actionColumnOptions: { actionColumns: [ { columnId: 'add_issue', friendlyName: 'Add Issue', actionColumnButton: [ { label: 'Add', 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); }, }, ], }, ], }, initialState: { Dashboard: { ModuleButtons: ['CalculatedColumn', 'FormatColumn', 'SettingsPanel'], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'github_stars', 'bigStars', 'add_issue', 'comments', 'week_issue_change', 'github_watchers', 'language', 'license', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, CalculatedColumn: { CalculatedColumns: [ { ColumnId: 'bigStars', Query: { ScalarExpression: '[github_stars] * 10 ', }, FriendlyName: 'Big Stars', CalculatedColumnSettings: {DataType: 'number'}, }, ], }, FreeTextColumn: { FreeTextColumns: [ { ColumnId: 'comments', FriendlyName: 'Comments', FreeTextStoredValues: [ {PrimaryKey: 24195339, FreeText: 'Used by the US team'}, {PrimaryKey: 224663696, FreeText: 'My personal favourite'}, {PrimaryKey: 82095231, FreeText: 'Required by Support Team'}, ], FreeTextColumnSettings: { Aggregatable: false, DataType: 'text', }, }, ], }, }, }; ``` ```ts import {ColDef, ColGroupDef, ITooltipParams} from 'ag-grid-enterprise'; 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, }, { field: 'license', cellDataType: 'text', editable: false, enablePivot: true, enableRowGroup: true, }, { headerName: 'Special Columns', children: [ { colId: 'bigStars', type: ['calculatedColumn'], cellDataType: 'number', }, { colId: 'add_issue', type: ['actionColumn'], }, { colId: 'comments', type: ['freeTextColumn'], cellDataType: 'text', }, ], }, { 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, }, ]; ``` --- # Column Groups Expanded Collapsed Behaviour Canonical page: https://www.adaptabletools.com/docs/handbook-grouping-columns-expanded-collapsed - Column Groups in AdapTable can be configured to open as Expanded or Collapsed - Users are able to set exceptions to the default for certain Column Groups Developers can configure, when a Layout loads, the collapsed / expanded behaviour for Column Groups. This is done on a per-Layout basis using the `ColumnGroupValues` property in the [`Base Layout`](https://www.adaptabletools.com/docs/reference/layoutbase.md) object. Something very similar can be done for [Row Groups](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md) using the (almost identical) `RowGroupValues` property ### Understanding the ColumnGroupValues object The [`ColumnGroupValues`](https://www.adaptabletools.com/docs/reference/columngroupvalues.md) object consists of 2 alternative properties (only one of which can be chosen): - `ColumnGroupDefaultBehavior` - to set **default and consistent behaviour** - `ColumnGroupValuesWithExceptionKeys` - (optional) to list any specific **exceptions** as an array This allows you either to configure behaviour that never changes or to list exceptions. Consistent Behaviour If you want the behaviour of Column Groups to be consistent (i.e. never change and never save exceptions) then use the `ColumnGroupDefaultBehavior` option in `ColumnGroupValues`. The `ColumnGroupDefaultBehavior` property consists of 2 possible values: - `always-expanded` - `always-collapsed` ```ts ColumnGroupValues: { ColumnGroupDefaultBehavior: 'always-expanded', }, ``` List Exceptions If you wish to provide a default behaviour, but also set or save exceptions, use `ColumnGroupValuesWithExceptionKeys` property in `ColumnGroupValues`. The [`ColumnGroupValuesWithExceptionKeys`](https://www.adaptabletools.com/docs/reference/columngroupvalueswithexceptionkeys.md) object contains 2 properties: - `ColumnGroupDefaultBehavior` - contains 2 possible values used to set **default** behaviour: `expanded` and `collapsed` - `ExceptionGroupKeys` - lists the Ids of Column Groups which are exceptions to default behaviour, provided as an array: - Make sure to set the `groupId` property for the Column Group, if you wish to use it in Exceptions - e.g in Example below we will have set the `groupId` property for the Column Groups of Prices and Details ```ts // Set all Column Groups to be expanded except for Prices and Details ColumnGroupValues: { ColumnGroupDefaultBehavior: 'collapsed', ExceptionGroupKeys: ['Prices', 'Details'], }, ``` There are 4 posible use cases: | Use Case | Default Behaviour | Provide Exceptions | | ----------------------------------------------- | ------------------ | :----------------: | | All Groups are exanded | `always-expanded` | ❌ | | All Groups are collapsed | `always-collapsed` | ❌ | | All Groups are expanded, but exceptions listed | `expanded` | ✅ | | All Groups are collapsed, but exceptions listed | `collapsed` | ✅ | **Example: Column Groups: Expanded and Collapsed** Setting Column Groups to be Expanded or Collapsed - This example illustrates the different options for Expanding / Collapsing Column Groups. We provide 3 Column Groups: - `Github` - which shows `Github Starts` when expanded and `Github Watchers` when closed - `Issues & PRs` - which shows the 2 Issues columns when expanded and the 2 PRs columns when closed - `Dates` - which shows `Created` when expanded and `Updated` and `Pushed` when closed - We also provide 4 Table Layouts which demonstrate the different options: - `Always Expanded` - has ColumnGroupDefaultBehavior set to `always-expanded` - `Always Collapsed` - has ColumnGroupDefaultBehavior set to `always-collapsed` - `Collapsed Exceptions` - all Column Groups collapsed with exception of `Issues & PRs` - `Expanded Exceptions` - all Column Groups expanded with exception of `Issues & PRs` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Column Grouping Expand / Collapsed', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Always Expanded', Layouts: [ { TableColumns: [ 'name', 'github_stars', 'github_watchers', 'open_issues_count', 'open_pr_count', 'closed_issues_count', 'closed_pr_count', 'created_at', 'updated_at', 'pushed_at', 'language', 'license', 'description', ], Name: 'Always Expanded', ColumnGroupValues: { ColumnGroupDefaultBehavior: 'always-expanded', }, AutoSizeColumns: true, }, { TableColumns: [ 'name', 'github_stars', 'github_watchers', 'open_issues_count', 'open_pr_count', 'closed_issues_count', 'closed_pr_count', 'created_at', 'updated_at', 'pushed_at', 'language', 'license', 'description', ], Name: 'Always Collapsed', ColumnGroupValues: { ColumnGroupDefaultBehavior: 'always-collapsed', }, AutoSizeColumns: true, }, { TableColumns: [ 'name', 'github_stars', 'github_watchers', 'open_issues_count', 'open_pr_count', 'closed_issues_count', 'closed_pr_count', 'created_at', 'updated_at', 'pushed_at', 'language', 'license', 'description', ], Name: 'Collapsed Exceptions', ColumnGroupValues: { ColumnGroupDefaultBehavior: 'collapsed', ExceptionGroupKeys: ['issues_prs'], }, AutoSizeColumns: true, }, { TableColumns: [ 'name', 'github_stars', 'github_watchers', 'open_issues_count', 'open_pr_count', 'closed_issues_count', 'closed_pr_count', 'created_at', 'updated_at', 'pushed_at', 'language', 'license', 'description', ], Name: 'Expanded Exceptions', ColumnGroupValues: { ColumnGroupDefaultBehavior: 'expanded', ExceptionGroupKeys: ['issues_prs'], }, AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {ColDef, ColGroupDef} from 'ag-grid-enterprise'; export const columnDefs: (ColDef | ColGroupDef)[] = [ { field: 'id', cellDataType: 'number', hide: true, editable: false, }, { field: 'name', cellDataType: 'text', }, { headerName: 'Issues & Prs', marryChildren: true, groupId: 'issues_prs', children: [ { field: 'open_pr_count', headerName: 'Open PRs', cellDataType: 'number', columnGroupShow: 'open', }, { field: 'open_issues_count', headerName: 'Open Issues', cellDataType: 'number', columnGroupShow: 'open', }, { field: 'closed_pr_count', headerName: 'Closed PRs', cellDataType: 'number', columnGroupShow: 'closed', }, { field: 'closed_issues_count', headerName: 'Closed Issues', cellDataType: 'number', columnGroupShow: 'closed', }, ], }, { headerName: 'Dates', marryChildren: true, groupId: 'dates', children: [ { field: 'created_at', headerName: 'Created', cellDataType: 'date', columnGroupShow: 'open', }, { field: 'updated_at', headerName: 'Updated', cellDataType: 'date', columnGroupShow: 'closed', }, { field: 'pushed_at', headerName: 'Pushed', cellDataType: 'date', columnGroupShow: 'closed', }, ], }, { headerName: 'Github', marryChildren: true, groupId: 'github', children: [ { field: 'github_stars', headerName: 'GitHub Stars', cellDataType: 'number', enableValue: true, columnGroupShow: 'open', }, { field: 'github_watchers', headerName: 'GitHub Watchers', cellDataType: 'number', enableValue: true, columnGroupShow: 'closed', }, ], }, { headerName: 'Details', marryChildren: true, groupId: 'details', children: [ { field: 'license', cellDataType: 'text', editable: false, enablePivot: true, enableRowGroup: true, columnGroupShow: 'open', }, { field: 'language', cellDataType: 'text', enablePivot: true, enableRowGroup: true, columnGroupShow: 'open', }, { field: 'description', cellDataType: 'text', sortable: false, columnGroupShow: 'closed', }, ], }, {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: 'week_issue_change', headerName: 'Issue Change', cellDataType: 'number', enableValue: true, }, ]; ``` ## Pivot Layouts The same behaviour is also available for the Pivot Column Groups which are displayed in [Pivot Layouts](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md). See [Pivot Layout: Pivot Column Groups](https://www.adaptabletools.com/docs/handbook-layouts-pivot-column-groups/index.md) for more detailed information and a demo (similar to the one above) --- # Formatting Column Groups Canonical page: https://www.adaptabletools.com/docs/handbook-grouping-columns-formatting - Columns in Column Groups can be formatted depending on whether the Group is Expanded or Collapsed By default all Columns placed inside Column Groups will be [styled and formatted](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) normally, and irrespective of whether the Column Group is expanded or collapsed. However it is possible to stipulate that a Column is only formatted if the Column Group in which it is situated is expanded (or collapsed). This is particularly useful when using [Pivot Column Groups](https://www.adaptabletools.com/docs/handbook-layouts-pivot-column-groups/index.md) and [Pivot Total Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md) This is done using the `ColumnGroupScope` property in the Format Column object which can take 3 values: - `Both` (the default) - `Expanded` - `Collapsed` `Both` will **not** be applied to top-level columns which don't have a parent group **Example: Column Groups: Expanded and Collapsed** Setting Column Groups to be Expanded or Collapsed - In this example we have created [Format Column Styles](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md) on 3 Columns inside Column Groups - each with a different behaviour (set via the `ColumnGroupScope` property): - The `Issue Change` column is set to `Both` - which is why the Style is visible when the `Issues & PRs` Column Group is both expanded and collapsed - The `Github Stars` column is set to `Collapsed` - which is why the Style is visible when the `Details` Column Group is collapsed (but not expanded) - The `Github Watchers` column is set to `Expanded` - which is why the Style is visible when the `Details` Column Group is expanded (but not collapses) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Column Grouping Formatting', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'All Expanded', Layouts: [ { TableColumns: [ 'name', 'week_issue_change', 'open_issues_count', 'open_pr_count', 'closed_issues_count', 'closed_pr_count', 'github_stars', 'github_watchers', 'created_at', 'updated_at', 'pushed_at', 'language', 'license', 'description', ], Name: 'All Expanded', ColumnGroupValues: { ColumnGroupDefaultBehavior: 'always-expanded', }, AutoSizeColumns: true, }, { TableColumns: [ 'name', 'week_issue_change', 'open_issues_count', 'open_pr_count', 'closed_issues_count', 'closed_pr_count', 'github_stars', 'github_watchers', 'created_at', 'updated_at', 'pushed_at', 'language', 'license', 'description', ], Name: 'All Collapsed', ColumnGroupValues: { ColumnGroupDefaultBehavior: 'always-collapsed', }, AutoSizeColumns: true, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-week_issue_change', Scope: { ColumnIds: ['week_issue_change'], }, Style: { BackColor: 'Blue', ForeColor: 'White', FontWeight: 'Bold', Alignment: 'Right', }, ColumnGroupScope: 'Both', }, { Name: 'formatColumn-github_stars', Scope: { ColumnIds: ['github_stars'], }, Style: { BackColor: 'Green', ForeColor: 'White', FontWeight: 'Bold', Alignment: 'Right', }, ColumnGroupScope: 'Collapsed', }, { Name: 'formatColumn-github_watchers', Scope: { ColumnIds: ['github_watchers'], }, Style: { BackColor: 'Red', ForeColor: 'White', FontWeight: 'Bold', Alignment: 'Right', }, ColumnGroupScope: 'Expanded', }, ], }, }, }; ``` ```ts import {ColDef, ColGroupDef} from 'ag-grid-enterprise'; export const columnDefs: (ColDef | ColGroupDef)[] = [ { field: 'id', cellDataType: 'number', hide: true, editable: false, }, { field: 'name', cellDataType: 'text', }, { headerName: 'Issues & PRs', marryChildren: true, groupId: 'issues_prs', children: [ { field: 'week_issue_change', headerName: 'Issue Change', cellDataType: 'number', enableValue: true, }, { field: 'open_pr_count', headerName: 'Open PRs', cellDataType: 'number', columnGroupShow: 'open', }, { field: 'open_issues_count', headerName: 'Open Issues', cellDataType: 'number', columnGroupShow: 'open', }, { field: 'closed_pr_count', headerName: 'Closed PRs', cellDataType: 'number', columnGroupShow: 'closed', }, { field: 'closed_issues_count', headerName: 'Closed Issues', cellDataType: 'number', columnGroupShow: 'closed', }, ], }, { headerName: 'Details', marryChildren: true, groupId: 'details', children: [ { field: 'github_stars', headerName: 'GitHub Stars', cellDataType: 'number', enableValue: true, }, { field: 'github_watchers', headerName: 'GitHub Watchers', cellDataType: 'number', enableValue: true, }, { field: 'created_at', headerName: 'Created', cellDataType: 'date', columnGroupShow: 'closed', }, { field: 'updated_at', headerName: 'Updated', cellDataType: 'date', columnGroupShow: 'closed', }, { field: 'pushed_at', headerName: 'Pushed', cellDataType: 'date', columnGroupShow: 'closed', }, ], }, { field: 'github_stars', headerName: 'GitHub Stars', cellDataType: 'number', enableValue: true, columnGroupShow: 'open', }, { field: 'github_watchers', headerName: 'GitHub Watchers', cellDataType: 'number', enableValue: true, columnGroupShow: 'closed', }, { field: 'license', cellDataType: 'text', editable: false, enablePivot: true, enableRowGroup: true, columnGroupShow: 'open', }, { field: 'language', cellDataType: 'text', enablePivot: true, enableRowGroup: true, columnGroupShow: 'open', }, { field: 'description', cellDataType: 'text', sortable: false, columnGroupShow: 'closed', }, {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: 'week_issue_change', headerName: 'Issue Change', cellDataType: 'number', enableValue: true, }, ]; ``` --- # Pivoting Canonical page: https://www.adaptabletools.com/docs/handbook-grouping-pivoting - AdapTable provides comprehensive support for AG Grid pivoting - This is available using dedicated **Pivot Layouts** which allow users and developers to configure complex pivoting setups - Popular features include: - the ability to click on any pivot grid cell and see the underlying values as a table - Pivot Total Columns - Please read the [Pivot Layouts](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md) documentation for full details of Pivoting in AdapTable --- # Row Grouping Canonical page: https://www.adaptabletools.com/docs/handbook-grouping-rows - AdapTable fully supports AG Grid Row Grouping and additionally provides a few related features - Row Groups can be defined in Layouts and currently expanded Row Groups can be persisted AG Grid makes it very easy for you to group your data through [Row Grouping](https://www.ag-grid.com/javascript-data-grid/grouping/). AdapTable adds a number helpful features and options to improve the Row Grouping experience. Row Groups in AdapTable are defined (and saved) in [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) (both Table and Pivot) - For [Table Layouts](https://www.adaptabletools.com/docs/handbook-layouts-table/index.md) use the `RowGroupedColumns` property - For [Pivot Layouts](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md) use the `PivotGroupedColumns` property **Example: Row Grouping: Basics** Configuring Row Groups in AdapTable - This Demo creates a Layout with Row Grouping (entitled `Grouped Layout`) which it sets as the Current Layout. It has the following features: - **2 Row Grouping Columns**: `language` and `license` - **2 (SUM) Aggregations**: AG Grid calculates & displays each Column value for `Github Watchers` & `Github Stars` in the Grouped Row - We use the AG Grid api to open the 'Columns' [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) so its easier to see what has been set ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Basic', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Grouped Layout', Layouts: [ { Name: 'Grouped Layout', RowGroupedColumns: ['language', 'license'], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'license', 'description', 'created_at', ], AutoSizeColumns: true, }, { TableColumns: [ 'name', 'github_stars', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'github_watchers', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Single Grouping Layout', RowGroupedColumns: ['language', 'license'], RowGroupDisplayType: 'single', RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, AutoSizeColumns: true, }, { TableColumns: [ 'name', 'github_stars', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'github_watchers', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Multi Grouping Layout', RowGroupedColumns: ['language', 'license'], RowGroupDisplayType: 'multi', RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, 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, rowGroupPanelShow: 'always', 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'); }; ``` # Defining Row Groups Row Groups can be defined in both Table Layouts and Pivot Layouts ### Defining a Table Layout with Row Grouping The `RowGroupedColumns` property is an array of (string) ColumnId This defines the **order** in which Columns will be row-grouped. The Rows in the Group will be sorted using the Column's default sort order (including Custom Sorts if they have been provided). By default Row Grouped Columns are always placed at the left of the Grid but the Layout definition can [position them anywhere](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md#positioning-row-groups) By default all Row Grouped Columns appear in one Column (named "Group"). Use `RowGroupDisplayType` property to change this to 'multi' (default is 'single') The Layout can be configured so that all, none or a defined list of Row Groups are expanded / collapsed when it opens. See [Row Groups Expanded / Collapsed Behaviour](https://www.adaptabletools.com/docs/handbook-grouping-rows-expanded-collapsed/index.md) for full details ```ts [[1, 12, "RowGroupedColumns"], [2, 13, "RowGroupDisplayType"], [3, 14, "RowGroupValues"]] // Define a Grouping and Aggregation Layout called "Grouping Layout" as follows: // AG Grid Row Grouping on 2 Columns: 'license' and 'language' // RowGroupDisplayType is multi (so each Row Group has own column) // Row Groups to be collapsed when Layout loads (with 4 exceptions listed) const initialState: InitialState = { Layout: { CurrentLayout: 'Grouping Layout', Layouts: [ { Name: 'Grouping Layout', TableColumns: ['github_stars', 'open_pr_count', 'github_watchers', 'examResult', 'attendance'], RowGroupedColumns: ['license', 'language'], RowGroupDisplayType: 'multi', RowGroupValues: { RowGroupDefaultBehavior: 'collapsed', GroupKeys: [ { RowGroupedColumns: ['language', 'license'], ExceptionGroupKeys: [ ['TypeScript'], ['TypeScript', 'MIT License'], ['JavaScript'], ['JavaScript', 'Other'], ], }, ], }, }], }, } ``` ### Defining a Pivot Layout with Row Grouping The `PivotGroupedColumns` property is an array of (string) ColumnId This defines the **order** in which Columns will be row-grouped. The Rows in the Group will be sorted using the Column's default sort order (including Custom Sorts if they have been provided). By default Row Grouped Columns are always placed at the left of the Grid but the Layout definition can [position them anywhere](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md#positioning-row-groups) By default all Row Grouped Columns appear in one Column (named "Group"). Use `RowGroupDisplayType` property to change this to 'multi' (default is 'single') The Layout can be configured so that all, none or a defined list of Row Groups are expanded / collapsed when it opens. See [Row Groups Expanded / Collapsed Behaviour](https://www.adaptabletools.com/docs/handbook-grouping-rows-expanded-collapsed/index.md) for full details ```ts [[1, 12, "PivotGroupedColumns"], [2, 13, "RowGroupDisplayType"], [3, 14, "RowGroupValues"]] // Define a Pivot Layout called "Grouping Layout" as follows: // AG Grid Row Grouping on 2 Columns: 'country' and 'counterparty' // RowGroupDisplayType is multi (so each Row Group has own column) // Row Groups to be expanded when Layout loads const initialState: InitialState = { Layout: { CurrentLayout: 'Grouping Layout', Layouts: [ { Name: 'Grouping Layout', PivotColumns: ['currency'], PivotGroupedColumns: ['country', 'counterparty'], RowGroupDisplayType: 'multi', RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, }], }, } ``` ## Multiple Row Group Columns AG Grid can been configured to show each Row Group in a **separate** column. This is supported by AdapTable by the `RowGroupDisplayType` property in each [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md). - AdapTable **ignores** AG Grid's `groupDisplayType` property if the `RowGroupDisplayType` property is set - i.e. if `RowGroupDisplayType` is *multi*, multiple row group cols are displayed, even if AG Grid is set to 'singleColumn' When this property is set to `multi`, AdapTable will: - display each Row Group in its own Column - use the Column's Friendly Name as the Header (instead of "Group") See below for instructions on positioning and pinning Row Group Columns when `RowGroupDisplayType` is *multi* - There is another option for this value, `groupRows`, which sets the Grouped Row to be full width - See [Grouped Rows](https://www.adaptabletools.com/docs/handbook-grouping-rows-grouped-rows/index.md) for full details **Example: Row Grouping: Multiple Columns** Displaying each Row Group in its own Column - This demo shows the options for Multi Row Grouping. We have via x Layouts (that both group by Language and License): - `MultiCol Grouped` - each Row Group has its own Column - `SingleCol Grouped` - both Row Groups are in the same Column ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Multiple Columns', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Multi Col Table', Layouts: [ { Name: 'Multi Col Table', RowGroupDisplayType: 'multi', RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, RowGroupedColumns: ['language', 'license'], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'github_watchers', 'updated_at', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'Single Col Table', RowGroupDisplayType: 'single', //the default RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, RowGroupedColumns: ['language', 'license'], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'github_watchers', 'updated_at', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'Multi Col Pivot', RowGroupDisplayType: 'multi', RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, PivotGroupedColumns: ['language', 'license'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, PivotColumns: ['has_wiki'], AutoSizeColumns: true, }, { Name: 'Single Col Pivot', RowGroupDisplayType: 'single', //the default RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, PivotGroupedColumns: ['language', 'license'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, PivotColumns: ['has_wiki'], 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, rowGroupPanelShow: 'always', groupDisplayType: 'singleColumn', statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` ## Expanded / Collapsed Row Groups Developers can configure, when a Layout loads, what is the collapsed or expanded behaviour for Row Groups. They can also provide exceptions, and save the currently expanded (or collapsed) Row Groups to State. See [Row Groups Expanded and Collapsed Behaviour](https://www.adaptabletools.com/docs/handbook-grouping-rows-expanded-collapsed/index.md) for full details and accompanying demos ## Managing Row Groups Row Grouped Columns can be managed in similar ways to other columns, i.e. they can be: - [formatted and styled](https://www.adaptabletools.com/docs/handbook-grouping-rows-formatting/index.md) - [sorted](https://www.adaptabletools.com/docs/handbook-grouping-rows-sorting/index.md) - [filtered](https://www.adaptabletools.com/docs/handbook-grouping-rows-filtering/index.md) ## Positioning Row Groups Row Grouped Columns are most typically placed in the first column of the Grid to the left of all other Columns. However AG Grid allows Row Grouped columns to be positioned anywhere in the Grid. This is fully supported by AdapTable and it will store the columns' positions accurately in the [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md). Currently it is **not** possible to re-position Row Groups in the Layout Wizard - but that behaviour is coming soon Additionally, it is possible to define a Layout in Initial State where the Row Group is not the first Column. ### Configuring Row Group Position in Layout Definitions If you want the Row Groups to be positioned at the left of the Grid - the default behaviour - then nothing additional is required to what is described in [Defining Row Groups in Layouts](https://www.adaptabletools.com/docs/handbook-layouts-table/index.md). However, in order to position a Row Grouped Column **not** at the left of the Grid, you need to add "ag-Grid-AutoColumn" into the `TableColumns` (array) property in the Layout Definition at the required position. For instance to place the Row Group Column as the second Column, the Layout should look like this: ```tsx Layouts: [ { Name: 'Grouped Layout', RowGroupedColumns: ['language', 'license'], TableColumns: [ 'name', 'ag-Grid-AutoColumn', 'github_stars', 'github_watchers', 'updated_at', 'pushed_at', 'description', 'created_at', ], }], ``` **Example: Row Grouping: Positioning Single** Positioning Single Row Groups in AdapTable - In this example we have configured Row Grouping on 2 columns:`Language` and `License` Columns - However, we have defined the Row Group Column to be the **second** Column - We have also added pinning to the first 2 columns (`Name` and the Row-Grouped Column) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Positioning Single', initialState: { Dashboard: { PinnedToolbars: ['Layout'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Grouped Layout', Layouts: [ { Name: 'Grouped Layout', RowGroupedColumns: ['language', 'license'], ColumnPinning: {name: 'left', 'ag-Grid-AutoColumn': 'left'}, TableColumns: [ 'name', 'ag-Grid-AutoColumn', 'github_stars', 'github_watchers', 'updated_at', 'pushed_at', 'description', 'created_at', ], 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, rowGroupPanelShow: 'always', 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'); }; ``` ### Positioning Multi Row Groups As noted above, AdapTable supports displaying each Row Group in a **separate** column. This includes positioning the multiple Row Group Columns so they are not displayed at the start of the Grid. ### Configuring Multiple Row Group Positions in Layout Definitions When AG Grid is showing multiple Row Group Columns (i.e. `RowGroupDisplayType` has been set to 'multi' in the Layout), you need to list each Row Group separately. This is achieved by adding `ag-Grid-AutoColumn-` followed by the Column Id. For instance to group on the `language` and `license` columns you will set: ```tsx Layouts: [ { Name: 'Grouped Layout', RowGroupedColumns: ['language', 'license'], TableColumns: [ 'name', 'ag-Grid-AutoColumn-language', 'ag-Grid-AutoColumn-license', 'github_stars', 'github_watchers', 'updated_at', 'pushed_at', 'description', 'created_at', ], }], ``` Note: this allows you to put the Row Grouped Columns wherever you want and in any order, e.g.: ```tsx Layouts: [ { Name: 'Grouped Layout', RowGroupedColumns: ['language', 'license'], TableColumns: [ 'name', 'ag-Grid-AutoColumn-license', 'github_stars', 'github_watchers', 'updated_at', 'ag-Grid-AutoColumn-language', 'pushed_at', 'description', 'created_at', ], }], ``` **Example: Row Grouping: Positioning Multiple** Positioning Multiple Row Groups in AdapTable - Here we Row Group on `Language` and `License` Columns (as in demo above), but AG Grid has been set to show Multiple Row Group columns - Accordingly we have defined AdapTable to display 2 Row Group Columns (as **second** and **third** Columns - but they can be positioned anywhere) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Positioning Multiple', initialState: { Dashboard: { PinnedToolbars: ['Layout'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Grouped Layout', Layouts: [ { Name: 'Grouped Layout', RowGroupedColumns: ['language', 'license'], TableColumns: [ 'name', 'ag-Grid-AutoColumn-language', 'ag-Grid-AutoColumn-license', 'github_stars', 'github_watchers', 'updated_at', 'pushed_at', 'description', 'created_at', ], 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, rowGroupPanelShow: 'always', groupDisplayType: 'multipleColumns', 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'); }; ``` ## Pinning Row Groups Row Grouped Columns can be pinned. This is done by adding 'ag-Grid-AutoColumn' to the `ColumnPinning` property in the Layout definition. **Example: Row Grouping: Pinning Single Row Group** Pinning Single Row Grouped Columns in AdapTable - This example we are grouping on the `Language` Column and we pinned it to the left ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Pinning Single', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pinned Grouped Single Layout', Layouts: [ { Name: 'Pinned Grouped Single Layout', RowGroupedColumns: ['language'], RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, RowGroupDisplayType: 'single', TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnPinning: {'ag-Grid-AutoColumn': 'left'}, SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'github_watchers', 'updated_at', 'license', 'description', 'created_at', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], AutoSizeColumns: true, }, { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', ], 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, rowGroupPanelShow: 'always', statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` ### Pinning Multi Row Groups When AG Grid is showing multiple Row Group Columns (i.e. `RowGroupDisplayType` has been set to 'multi' in the Layout), you need to list each Row Group separately. This is achieved by adding `ag-Grid-AutoColumn-` followed by the Column Id. The same thing is required whenever you set `RowGroupDisplayType` to 'multi' - see Positioning Multi Groups above **Example: Row Grouping: Pinning Multiple Row Groups** Pinning Multiple Row Grouped Columns in AdapTable - This example we are grouping on the `Language` Column and we pinned it to the left ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Pinning Multi', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pinned Grouped Multi Layout', Layouts: [ { Name: 'Pinned Grouped Multi Layout', RowGroupedColumns: ['language', 'license'], RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, RowGroupDisplayType: 'multi', TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnPinning: { 'ag-Grid-AutoColumn-language': 'left', 'ag-Grid-AutoColumn-license': 'left', }, SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'github_watchers', 'updated_at', 'description', 'created_at', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], AutoSizeColumns: true, }, { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', ], 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, rowGroupPanelShow: 'always', statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` ## Sizing Row Groups Row Grouped Columns can be given custom widths. This is done by adding 'ag-Grid-AutoColumn' to the `ColumnSizing` property in the Layout definition. **Example: Row Grouping: Sizing Row Group Column** Sizing Row Grouped Columns in AdapTable - This example we are grouping on the `License` Column and we gave it a width of 350px ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Width', initialState: { Dashboard: { ModuleButtons: ['SettingsPanel'], Tabs: [ { Name: 'Default', Toolbars: ['Layout'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Row Grouping Widths Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'topics', 'open_pr_count', 'closed_pr_count', ], RowGroupedColumns: ['license'], ColumnSizing: {'ag-Grid-AutoColumn': {Width: 350}}, Name: 'Row Grouping Widths Layout', }, ], }, }, }; ``` ```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, rowGroupPanelShow: 'always', statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` --- # Row Grouping Expanded Collapsed Behaviour Canonical page: https://www.adaptabletools.com/docs/handbook-grouping-rows-expanded-collapsed - Row Groups in AdapTable can be configured to open as Expanded or Collapsed - Users are able to set exceptions to the default for certain Row Groups - The same functionality is available in both Table and Pivot Layouts Developers can configure, when a Layout loads, the collapsed / expanded behaviour for Row Groups. This is done on a per-Layout basis using the `RowGroupValues` property in the [`Base Layout`](https://www.adaptabletools.com/docs/reference/layoutbase.md) object. This behaviour is available - and identical - in 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). Something very similar is available for [Column Groups](https://www.adaptabletools.com/docs/handbook-grouping-columns-expanded-collapsed/index.md) using the `ColumnGroupValues` property ### Understanding the RowGroupValues Object Row Group Values are set using the [`RowGroupValues`](https://www.adaptabletools.com/docs/reference/rowgroupvalues.md) object. This object consists of 2 alternative properties (only one of which can be chosen): - `RowGroupDefaultBehavior` - to set **consistent behaviour** - `RowGroupValuesWithExceptionKeys` - (optional) to list any specific **exceptions** In other words you can choose whether to configure **consistent** behaviour that never changes, or to **list exceptions**. Consistent Behaviour If you want the behaviour of Row Groups to be consistent (i.e. never change and never save exceptions) then use the `RowGroupDefaultBehavior` option in `RowGroupValues`. The `RowGroupDefaultBehavior` property consists of 2 possible values: - `always-expanded` ```ts {3} // Set all row groups always to be expanded RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, ``` - `always-collapsed` ```ts {3} // Set all row groups always to be collapsed RowGroupValues: { RowGroupDefaultBehavior: 'always-collapsed', }, ``` List Exceptions If you wish to provide a default behaviour, but also set or save exceptions, use the `RowGroupValuesWithExceptionKeys` property in `RowGroupValues`. This alllows you to configure the expand / collapse behaviour for each specific combination of row grouped columns. The [`RowGroupValuesWithExceptionKeys`](https://www.adaptabletools.com/docs/reference/rowgroupvalueswithexceptionkeys.md) object contains 2 properties: - `RowGroupDefaultBehavior` - can be one of 2 possible values, used to set **default** behaviour: - `expanded` - `collapsed` - `GroupKeys` - provides per Row Grouped Column **exceptions** (listed by key) - Previously AdapTable provided the `ExceptionGroupKeys` prop which simply listed all exceptions - This is **deprecated** and replaced with `GroupKeys` which enables per Row Grouped Column exceptions The [`GroupKeys`](https://www.adaptabletools.com/docs/reference/groupkeys.md) object is defined as follows: | Property | Type | Description | | --- | --- | --- | | [ExceptionGroupKeys](https://www.adaptabletools.com/docs/reference/groupkeys.md#exceptiongroupkeys) | `any[][]` | Exceptions to default behaviour, provided as array or arrays | | [RowGroupedColumns](https://www.adaptabletools.com/docs/reference/groupkeys.md#rowgroupedcolumns) | `string[]` | Columns that are Row Grouped | ```ts {3,4} // Set all row groups always to be collapsed with exceptions for Language and License columns RowGroupValues: { RowGroupDefaultBehavior: 'collapsed', GroupKeys: [ { RowGroupedColumns: ['language'], ExceptionGroupKeys: [['TypeScript'],['JavaScript']], }, { RowGroupedColumns: ['license'], ExceptionGroupKeys: [['MIT License']], }, ], }, ``` This allows you to provide exceptions also when using Multi-Row Grouping: ```ts {3,4} // Set all row groups always to be collapsed with a few exceptions RowGroupValues: { RowGroupDefaultBehavior: 'collapsed', GroupKeys: [ { RowGroupedColumns: ['language', 'license'], ExceptionGroupKeys: [ ['TypeScript'], ['TypeScript', 'MIT License'], ['JavaScript'], ['JavaScript', 'Other'], ], }, ], }, ``` There are 4 posible use cases for setting expanded / collapsed behaviour: | Use Case | Default Behaviour | Provide Exceptions | | ----------------------------------------------- | ------------------ | :----------------: | | All Groups are always exanded | `always-expanded` | ❌ | | All Groups are always collapsed | `always-collapsed` | ❌ | | All Groups are expanded, but exceptions listed | `expanded` | ✅ | | All Groups are collapsed, but exceptions listed | `collapsed` | ✅ | ## Consistent Behaviour Each Layout can specify whether all Row Groups are expanded, or are all collapsed, whenever it opens. This is done via the `RowGroupDefaultBehavior` property in `RowGroupValues` which can be set to one of 2 values: - `always-expanded` - every Row Group is always expanded whenever the Layout is selected - `always-collapsed` - every Row Group is always collapsed whenever the Layout is selected **Example: Row Grouping: Setting Default Behaviour** Default Row Group Behaviour - This demo defines 2 Table Layouts in which Row Group behaviour is set, to show no exceptions, when the Layout opens, by configuring the `RowGroupValues` property: - `Always Expanded` has `RowGroupDefaultBehavior` set to **always-expanded** so all Row Groups are open - `Always Collapsed` has `RowGroupDefaultBehavior` set to **always-collapsed** so all Row Groups are closed ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping Default Behaviour', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Always Expanded', Layouts: [ { Name: 'Always Expanded', RowGroupedColumns: ['language', 'license'], RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'license', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'Always Collapsed', RowGroupedColumns: ['language', 'license'], RowGroupValues: { RowGroupDefaultBehavior: 'always-collapsed', }, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'license', 'description', 'created_at', ], 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, rowGroupPanelShow: 'always', groupDisplayType: 'multipleColumns', statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` ## Listing Exceptions Layouts also offer a more fine-grained approach to Row Group expanded and collapsed behaviour. Developers can configure the default behaviour, while saving exceptions on a per-Row Grouped Column basis. This is also using the `RowGroupValues` object, but this time 2 properties are required: - `RowGroupDefaultBehavior`: can be set to `expanded` or `collapsed` - `GroupKeys`: contains `RowGroupedColumns` (array of ColIds) and `ExceptionGroupKeys` (array of Col values) ### One Row Group Column When there is just one Column being Row-Grouped, it is straightforward to set the Exceptions. ```ts {3,6,7} // Set default behaviour of collapsed with 2 exceptions when grouping by Language RowGroupValues: { RowGroupDefaultBehavior: 'collapsed', GroupKeys: [ { RowGroupedColumns: ['language'], ExceptionGroupKeys: [['TypeScript'],['JavaScript']], }], } ``` **Example: Row Grouping Behaviour: Single Row Grouping** Setting and Saving Expanded Single Row Groups - In this demo we set the `RowGroupDefaultBehavior` with exceptions for single Row Grouped Columns: - `Single Grouping Collapsed Layout` has behaviour set to **collapsed** with exceptions for 2 Columns: - `Language` column - exceptions for "JavaScript" and "HTML" - `License` column - exception for "Other" - `Single Grouping Expanded Layout` has behaviour set to **expanded** with exception in `Language` column: "JavaScript" - In `Single Grouping Collapsed Layout` ungroup by `Language` and then group by `License` and note that the exception for "Other" is applied ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping Behaviour Exceptions Single', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Single Grouping Collapsed', Layouts: [ { Name: 'Single Grouping Collapsed', RowGroupedColumns: ['language'], RowGroupValues: { RowGroupDefaultBehavior: 'collapsed', GroupKeys: [ { RowGroupedColumns: ['language'], ExceptionGroupKeys: [['JavaScript'], ['HTML']], }, { RowGroupedColumns: ['license'], ExceptionGroupKeys: [['Other']], }, ], }, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'license', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'Single Grouping Expanded', RowGroupedColumns: ['language'], RowGroupValues: { RowGroupDefaultBehavior: 'expanded', GroupKeys: [ { RowGroupedColumns: ['language'], ExceptionGroupKeys: [['JavaScript']], }, { RowGroupedColumns: ['license'], ExceptionGroupKeys: [['Other']], }, ], }, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'license', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', ], 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, rowGroupPanelShow: 'always', groupDisplayType: 'multipleColumns', statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` ### Many Row Group Columns When there is more than one Column being Row-Grouped, the Exceptions need to be set differently. The `ExceptionGroupKeys` should contain a comma separated list to match the columns. - This use case deals with multi row grouped columns in one "Group" Column (i.e. `RowGroupDisplayType` is single) - See below for setting exceptions when each Row Group is in its own Column (i.e. `RowGroupDisplayType` is multi) ```ts RowGroupValues: { RowGroupDefaultBehavior: 'collapsed', GroupKeys: [ { RowGroupedColumns: ['language', 'license'], ExceptionGroupKeys: [['HTML'], ['HTML', 'Other'], ['JavaScript'] ], }, ], } ``` **Example: Row Grouping Behaviour: Multiple Row Grouping** Setting and Saving Expanded Multiple Row Groups - In this demo we set the `RowGroupDefaultBehavior` with exceptions for multiple Row Grouped Columns - The `Multiple Grouping Collapsed Layout` groups by `Language` & `Licence` and behaviour set to **collapsed** with 3 exceptions: 'JavaScript', 'JavaScript/Other', 'HTML' ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping Default Behaviour Multi', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Multi Grouped Table Layout', Layouts: [ { Name: 'Multi Grouped Table Layout', RowGroupedColumns: ['language', 'license'], RowGroupValues: { RowGroupDefaultBehavior: 'collapsed', GroupKeys: [ { RowGroupedColumns: ['language', 'license'], ExceptionGroupKeys: [ ['JavaScript'], ['JavaScript', 'Other'], ['HTML'], ], }, ], }, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'license', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', ], 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, rowGroupPanelShow: 'always', groupDisplayType: 'multipleColumns', statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` ### Display Type Multi Row Group exceptions are also available when using Multi Display Types. This is when each Row Grouped Column is displayed in its own separate Column. The syntax for `GroupKeys` is the same as that used when using Multi Column Grouping. **Example: Row Grouping Behaviour: Display Type Multi** Setting and Saving Expanded Row Groups with DisplayType of Multi - In this demo we have provided 2 Layouts with `RowGroupDisplayType` of 'multi', with grouping on `Language` and `License` columns, and default behaviour of "collapsed": - In `Multi TypeScript` Layout we provide an exception for ["TypeScript"] (so that just that is expanded) - In `Multi HTML Other` Layout we provide an exceptions for ["HTML"] and ["HTML", "Other"] (so that just they are expanded) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping Behaviour RowGroupDisplayType multi', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Multi TypeScript', Layouts: [ { Name: 'Multi TypeScript', RowGroupedColumns: ['language', 'license'], RowGroupDisplayType: 'multi', RowGroupValues: { RowGroupDefaultBehavior: 'collapsed', GroupKeys: [ { RowGroupedColumns: ['language', 'license'], ExceptionGroupKeys: [['TypeScript']], }, ], }, TableColumns: [ 'name', 'github_stars', 'github_watchers', 'updated_at', 'description', 'created_at', 'topics', ], AutoSizeColumns: true, }, { Name: 'Multi HTML Other', RowGroupedColumns: ['language', 'license'], RowGroupDisplayType: 'multi', RowGroupValues: { RowGroupDefaultBehavior: 'collapsed', GroupKeys: [ { RowGroupedColumns: ['language', 'license'], ExceptionGroupKeys: [['HTML'], ['HTML', 'Other']], }, ], }, TableColumns: [ 'name', 'github_stars', 'github_watchers', 'updated_at', 'description', 'created_at', 'topics', ], AutoSizeColumns: true, }, { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', ], 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, rowGroupPanelShow: 'always', groupDisplayType: 'multipleColumns', statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` ## Pivot Layouts The expand / collapse behaviour is exactly the same for [Pivot Layouts](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md). You can either set a consistent behaviour or allow (and provide) exceptions to be saved. **Example: Row Grouping Behaviour: Pivot Layouts** Setting and Saving Expanded Row Groups in Pivot Layouts - In this demo we have provided Pivot 2 Layouts with grouping on `Language` and `License` columns: - `Pivot Layout Consistent` has default behaviour of "always-expanded" so every group is expanded - `Pivot Layout Exceptions` has default behaviour of "collapsed" but with initial exceptions for *JavaScript* and *HTML* (so that they are both expanded) - Close some groups in `Pivot Layout Consistent` and then switch Layouts and back and note that the Groups are expanded again when the Layout is reloaded - Close /expand some groups in `Pivot Layout Expanded` and note that these changes are re-rendered when the Layout is reloaded ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping Behaviour Pivot Layouts', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Layout Consistent', Layouts: [ { Name: 'Pivot Layout Consistent', PivotColumns: ['has_wiki'], PivotGroupedColumns: ['language', 'license'], RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'count', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, { Name: 'Pivot Layout Exceptions', PivotColumns: ['has_wiki'], PivotGroupedColumns: ['language', 'license'], RowGroupValues: { RowGroupDefaultBehavior: 'collapsed', GroupKeys: [ { RowGroupedColumns: ['language', 'license'], ExceptionGroupKeys: [['JavaScript'], ['HTML']], }, ], }, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'count', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, ], }, }, }; ``` ```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, rowGroupPanelShow: 'always', groupDisplayType: 'multipleColumns', statusBar: { statusPanels: [ {statusPanel: 'agTotalRowCountComponent', align: 'left'}, {statusPanel: 'agFilteredRowCountComponent'}, { key: 'Center Panel', statusPanel: 'AdaptableStatusPanel', align: 'center', }, ], }, }; ``` --- # Row Grouping - Filtering Canonical page: https://www.adaptabletools.com/docs/handbook-grouping-rows-filtering - Row Grouped Columns can be filtered like any other Column - When there are multiple Row-Grouped Columns, AdapTable provides a Tree-based structure Row Grouped Columns can be [filtered](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) like any other column. - If a Column being Row-Grouped is already filtered, then the filter will apply to the Row Group - Only the values that currently appear in the column being grouped, will display in the Row Group filter AdapTable's Row Grouped column filter behaviour differs based on the value of the Layout's `RowGroupDisplayType` property which can be: - `single`- all Row Group Columns appear in one column - `multi` - each Row Grouped Column appears in its own Column ## `RowGroupDisplayType`: Single When the `RowGroupDisplayType` is *single*, AG Grid will display one Column for all Row Grouped Columns. AdapTable will automatically change the default Predicate to the [In Filter](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md). Make sure to set `floatingFilter` to *true* in AG Grid `GridOptions` The look and feel of the `In` Filter values differs depending on how many Columns are being Row Grouped: - one Column only - AdapTable will simply display a list of all distinct values in the Row Grouped Column - 2 (or more) Columns - AdapTable will show the grouped columns as an expandable **Tree** structure (with a button to expand / collapse all "leafs" in the tree) **Example: Row Grouping: Filtering Single RowGroupDisplayType** Filtering Row Grouped Columns with Display Type Single - In this example we have provided 2 Layouts with `RowGroupDisplayType` set to *single*: - `DisplayType Single 1 Row Group` has just one Row Group (`Language` Column) and so values are displayed in a **list** - `DisplayType Single 2 Row Groups` has 2 Row Groups (`Language` and `License` Columns) and so values are displayed in a **tree** structure ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Filtering DisplayType Single', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout', 'ColumnFilter']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'DisplayType Single 1 Row Group', Layouts: [ { Name: 'DisplayType Single 1 Row Group', RowGroupedColumns: ['language'], RowGroupDisplayType: 'single', TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'github_watchers', 'license', 'updated_at', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'DisplayType Single 2 Row Groups', RowGroupedColumns: ['language', 'license'], RowGroupDisplayType: 'single', TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'github_watchers', 'updated_at', 'description', 'created_at', ], 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, }, autoGroupColumnDef: { floatingFilter: true, filter: 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'); }; ``` ### Pre-existing Column Filters If there are pre-existing Column Filters on a Column which is being Row Grouped, these will, of course, affect which rows are displayed in the Row Grouped Column. For instance, if the Column Filter means that just 2 rows pass as true, then only those 2 rows appear in the Row Grouped Column. However, the Filter list for the Row Grouped Column will still display **all** distinct values (either as a list or Tree). - This is because the Filter for the Row Grouped Column (in `RowGroupDisplayType`: single) is stored separately - It is not stored using the Row-Grouped Column's Id, but with a "special" columnId of `ag-Grid-AutoColumn` **Example: Row Grouping: Existing Filters** Filtering Row Grouped Columns on Columns with existing Column Filters - In this example we have provided 2 Column Filters - on the `Language` and `License` Columns, and we have also Row-Grouped on those 2 columns - As a result we only see 12 rows in the Grid (insted of 25) and no Row Group for "TypeScript" - However, when we open the `In` Filter dropdown for the Row Grouped Column we see all the distinct values (in a Tree structure), allowing us to create an **additional** Column Filter if we wish ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Existing Column Filters', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout', 'ColumnFilter']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Single Grouped Layout', Layouts: [ { Name: 'Row Grouped Layout', RowGroupedColumns: ['language', 'license'], RowGroupDisplayType: 'single', TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnFilters: [ { ColumnId: 'language', Predicates: [{PredicateId: 'In', Inputs: ['JavaScript', 'HTML']}], }, { ColumnId: 'license', Predicates: [{PredicateId: 'EndsWith', Inputs: ['se']}], }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'license', 'updated_at', 'description', 'created_at', ], 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, }, autoGroupColumnDef: { floatingFilter: true, filter: 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'); }; ``` ### Setting Grouped Column Filter As noted above, when using `RowGroupDisplayType` of *single*, the Column Filter for the Row Grouped Column is stored separately to those of the columns which are being Row-Grouped. It is stored using the special *columnId* of `ag-Grid-AutoColumn` (which is created dynamically by AG Grid). This allows you to create a Column Filter just for the Row Grouped Column, irrespective of any Filters applied to the Columns being Row Grouped. The Column Filter uses the `PredicateId` of `In` and the values are stored as an array of arrays, e.g. ``` ColumnFilters: [{ ColumnId: 'ag-Grid-AutoColumn', Predicates: [{ PredicateId: 'In', Inputs: [['JavaScript'], ['HTML', 'Other']] }] }] ``` **Example: Row Grouping: Setting Row Grouped Column Filter** Setting Filter for the Row Grouped Column - In this example we explicitly set a [Column Filter](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) on the Row Grouped Column (with PredicateId `In`) with 2 inputs: - `'JavaScript'` - so that the leaf of "JavaScript" and all sub-leaves and nodes are selected - `'HTML', 'Other'` - so that only the combination of HTML and Other is selected - We have also set a larger Column Size for the Row Grouped Column to make it easier to see which items have been Filtered - Open the Column Filter for the Row Grouped Column and note how the 2 items have been selected ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Setting Row Group Column Filter', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout', 'ColumnFilter']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Single Grouped Layout', Layouts: [ { Name: 'Row Grouped Layout', RowGroupedColumns: ['language', 'license'], RowGroupDisplayType: 'single', TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnFilters: [ { ColumnId: 'ag-Grid-AutoColumn', Predicates: [ { PredicateId: 'In', Inputs: [['JavaScript'], ['HTML', 'Other']], }, ], }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'license', 'updated_at', 'description', 'created_at', ], ColumnSizing: {'ag-Grid-AutoColumn': {Width: 250}}, 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, }, autoGroupColumnDef: { floatingFilter: true, filter: 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'); }; ``` ### Filtering the AG Grid Field AG Grid has a [neat option](https://www.ag-grid.com/javascript-data-grid/grouping-single-group-column/#configuration) that allows developers to set which Column's values will appear in the leaf rows of the Row Grouped Column. This is done by settting the `field` property in the `autoGroupColumnDef` section in Grid Options When this property is set, AdapTable will also apply the Tree List structure, allowing users easily to select from both the Column(s) being Row Grouped and the Column that is set as the `field`. - It is also possible to set the Filter when Field is set - This is done using the same array of arrays as when you have mutliple Row Grouped Columns **Example: Row Grouping: Filtering with Field** Setting Filter for the Row Grouped Column when Field is set - In this example we have set the `field` property in `autoGroupColumnDef` to be the `Name` column - As a result, AG Grid displays the `Name` Column's values when you open a Row Group - AdapTable follows suit for the Row Grouped Column's Column Filter, allowing you to see the same structure (and to select values to filter from both Columns) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Filtering With Field', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout', 'ColumnFilter']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Row Grouped Layout', Layouts: [ { Name: 'Row Grouped Layout', RowGroupedColumns: ['language'], RowGroupDisplayType: 'single', TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'github_stars', 'github_watchers', 'license', 'updated_at', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'Row Grouped Filtered Layout', RowGroupedColumns: ['language'], RowGroupDisplayType: 'single', TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSizing: {'ag-Grid-AutoColumn': {Width: 350}}, ColumnFilters: [ { ColumnId: 'ag-Grid-AutoColumn', Predicates: [ { PredicateId: 'In', Inputs: [ ['JavaScript'], ['TypeScript', 'angular'], ['TypeScript', 'svelte'], ], }, ], }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'github_stars', 'github_watchers', 'license', 'updated_at', 'description', 'created_at', ], 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, }, autoGroupColumnDef: { floatingFilter: true, filter: true, field: 'name', }, 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'); }; ``` ## `RowGroupDisplayType`: Multi When the `RowGroupDisplayType` is *multi*, AG Grid will display each Row Grouped Column as a separate Column. Unlike with *single* Display Type, AdapTable does very little as far as Filtering is concerned. Column Filters are created, and persisted, in exactly the same way for "normal" and Row-Grouped Columns. **Example: Row Grouping: Filtering Multi RowGroupDisplayType** Filtering Row Grouped Columns with Display Type Multi - In this example we have provided a Layout with `RowGroupDisplayType` set to *multi* - We have Row Grouped on the `Language` and `License` Columns, but each appears as its own Column - We have also created Column Filters on those 2 Columns which are evaluated, and displayed, identically irrespective of whether the Column is Row Grouped ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Filtering DisplayType Multi', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout', 'ColumnFilter']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'DisplayType Multi Unfiltered', Layouts: [ { Name: 'DisplayType Multi Filtered', RowGroupedColumns: ['language', 'license'], RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, RowGroupDisplayType: 'multi', TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnFilters: [ { ColumnId: 'language', Predicates: [{PredicateId: 'In', Inputs: ['JavaScript', 'HTML']}], }, { ColumnId: 'license', Predicates: [{PredicateId: 'EndsWith', Inputs: ['se']}], }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'language', 'license', 'name', 'github_stars', 'github_watchers', 'updated_at', 'description', 'created_at', ], 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, }, autoGroupColumnDef: { floatingFilter: true, filter: 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'); }; ``` --- # Row Grouping - Formatting and Styling Canonical page: https://www.adaptabletools.com/docs/handbook-grouping-rows-formatting - Row Grouped Columns can be formatted and styled - This is available for both Single and Multi Row Grouped Column Display Types AdapTable allows you to easily to format and style Row Grouped Columns - in both Table and Pivot Layouts. However this needs to be done explicitly - AdapTable will not use a Column's Style when it is Row Grouped. A column's Format Column will not be automically applied to the `Group` Column when you Row Group on that column Instead set the Column Scope of the Format Column to use AG Grid's automated colId. ## Single Display Type In Single Display Type grouping, AG Grid gives the Row Grouped column a ColId of 'ag-Grid-AutoColumn'. **Example: Row Grouping: Formatting Single** Formatting Row Grouped Columns - In this example we add a Format Column for 'ag-Grid-AutoColumn' of Brown Background, White Font and Italicised (and a Predicate of NonBlanks) - This format is automatically applied to the Row Grouped Column in the 2 Layouts provided: - In `Table Grouped Layout` the `License` Column is grouped and styled - In `Pivot Grouped Layout` the `Language` Column is grouped and has the same style ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Formatting Single Row Grouped Columns', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], ModuleButtons: ['FormatColumn', 'SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Table Grouped Layout', Layouts: [ { Name: 'Table Grouped Layout', TableColumns: [ 'name', 'language', 'github_stars', 'popularity', 'open_issues_count', 'created_at', 'has_wiki', ], RowGroupedColumns: ['license'], RowGroupValues: {RowGroupDefaultBehavior: 'always-expanded'}, AutoSizeColumns: true, }, { Name: 'Pivot Grouped Layout', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-grouped-column', Scope: { ColumnIds: ['ag-Grid-AutoColumn'], }, Rule: { Predicates: [ { PredicateId: 'NonBlanks', }, { PredicateId: 'Contains', Inputs: ['c'], }, ], }, Style: { BackColor: 'Brown', ForeColor: 'White', FontStyle: 'Italic', Alignment: 'Center', }, }, ], }, }, }; ``` ## Multi Display Type Row Groups can be configured to display in multiple columns (by setting `RowGroupDisplayType` to 'multi'). When this happens each Row Grouped Column appears in its own, named, Column. These Columns can also be formatted by setting the Column Scope, but this time it needs to be done explicity. This is done by appending the Column Id to 'ag-Grid-AutoColumn-' (e.g. 'ag-Grid-AutoColumn-license'). - This has the advantage that you can configure the Format or Style based on specific Column being Row Grouped - But it has the disadvantage that a Style will not be automatically applied to other Columns when Row Grouped **Example: Row Grouping: Formatting Multi** Formatting Multiple Row Grouped Columns - In this example we Row Group on License and Language Columns using `RowGroupDisplayType` of 'multi' - We add specific Format Columns to the Row Grouped Columns by using the ColumnIds 'ag-Grid-AutoColumn-license' and 'ag-Grid-AutoColumn-license' - Apply Row Grouping to different columns and note that they are not formatted or styled ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Formatting Multi Row Grouped Columns', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], ModuleButtons: ['FormatColumn', 'SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Grouped Layout', Layouts: [ { Name: 'Grouped Layout', TableColumns: [ 'name', 'github_stars', 'popularity', 'open_issues_count', 'created_at', 'has_wiki', ], RowGroupedColumns: ['license', 'language'], RowGroupDisplayType: 'multi', RowGroupValues: {RowGroupDefaultBehavior: 'always-expanded'}, AutoSizeColumns: true, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-license', Scope: { ColumnIds: ['ag-Grid-AutoColumn-license'], }, Rule: { Predicates: [ { PredicateId: 'NonBlanks', }, ], }, Style: { BackColor: 'Brown', ForeColor: 'White', FontStyle: 'Italic', Alignment: 'Center', }, }, { Name: 'formatColumn-language', Scope: { ColumnIds: ['ag-Grid-AutoColumn-language'], }, Rule: { Predicates: [ { PredicateId: 'NonBlanks', }, ], }, Style: { BackColor: 'Purple', ForeColor: 'White', FontWeight: 'Bold', Alignment: 'Center', }, }, ], }, }, }; ``` ## Conditional Styles Format Column on Row Groups can be conditional, ie. have a rule. Like all Conditional Styles this can be either a [Predicate](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) or an [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) and are evaluated normally. A common Predicate Condition is to add `NonBlanks` - to format only cells in the Row Grouped Column that have text There are a couple of small "gotchas" regarding creating Conditional Styles for Row Groups in the AdapTable UI: - Predicates can only be added in the UI to Layouts which have a `RowGroupDisplayType` of 'multi' - The Expression Editor allows Expressions to be written, but the Row Group Column itself is not listed (and therefore not available to be dragged into the Editor) **Example: Row Grouping: Conditional Styles** Providing Conditional Styling for Row Grouped Columns - In this example we create a Conditional Style on the Row Grouped Column of `"CONTAINS([ag-Grid-AutoColumn], 'c')"` - As a result in both the Table and Pivot Layout, only values in the Row Group column containing the letter "c" are styled ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Conditional Styles for Row Grouped Columns', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], ModuleButtons: ['FormatColumn', 'SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Table Grouped Layout', Layouts: [ { Name: 'Table Grouped Layout', TableColumns: [ 'name', 'language', 'github_stars', 'popularity', 'open_issues_count', 'created_at', 'has_wiki', ], RowGroupedColumns: ['license'], RowGroupValues: {RowGroupDefaultBehavior: 'always-collapsed'}, AutoSizeColumns: true, }, { Name: 'Pivot Grouped Layout', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-grouped-column', Scope: { ColumnIds: ['ag-Grid-AutoColumn'], }, Rule: { BooleanExpression: "CONTAINS([ag-Grid-AutoColumn], 'c')", }, Style: { BackColor: 'Brown', ForeColor: 'White', FontStyle: 'Italic', Alignment: 'Center', }, }, ], }, }, }; ``` ### Formatting Whole Row Like with all Conditional Styles the entire Row (in this case the Grouped Row) can be styled or formatted. This requires an Expression-based Rule with [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) of Whole Row **Example: Row Grouping: Styling Whole Grouped Row** Providing Conditional Styling for entire Row Grouped Column Row - This demo contains the same Expression (and Layouts) as the example above - The only difference is that the [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) is Whole Row - which is the entire row is styled (where it meets the condition) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Styling Full Row Grouped Column Row', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], ModuleButtons: ['FormatColumn', 'SettingsPanel'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Table Grouped Layout', Layouts: [ { Name: 'Table Grouped Layout', TableColumns: [ 'name', 'language', 'github_stars', 'popularity', 'open_issues_count', 'created_at', 'has_wiki', ], RowGroupedColumns: ['license'], RowGroupValues: {RowGroupDefaultBehavior: 'always-collapsed'}, AutoSizeColumns: true, }, { Name: 'Pivot Grouped Layout', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-grouped-column', Scope: { All: true, }, Rule: { BooleanExpression: "CONTAINS([ag-Grid-AutoColumn], 'c')", }, Style: { BackColor: 'Brown', ForeColor: 'White', FontStyle: 'Italic', Alignment: 'Center', }, }, ], }, }, }; ``` --- # Row Grouping - Grouped Rows Canonical page: https://www.adaptabletools.com/docs/handbook-grouping-rows-grouped-rows - Grouped Rows are the rows created by each Row Grouped Column value - AdapTable extends Formatting and Styled Columns to Grouped Rows (with per-type defaults) - Layouts can use **Full Width Group Rows** (`RowGroupDisplayType`: `groupRows`) — a separate display mode from multi-column groups [Grouped Rows](https://ag-grid.com/javascript-data-grid/grouping-group-rows/) are the Rows created by AG Grid when Row Grouping. There is one Grouped Row for each value in the Row Grouped Column. ## Full Width Group Rows AG Grid [provides an option](https://ag-grid.com/javascript-data-grid/grouping-group-rows/) to render each grouped row as a single **full-width** row. - Full width rows take UI precedence over Aggs defined in `TableAggregationColumns` which are not displayed - The aggregations are still calculated by AG Grid but you cannot see them in the Grouped Row AdapTable [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) also offers this functionality by setting the `RowGroupDisplayType` property to `groupRows`. - The two other potential values for this property are `single` and `multi` - They allow you to choose [single or multiple Row Grouped Columns](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md#multiple-row-group-columns) and both will display aggregations The AdapTable Layout is the single source of truth for full width rows and overrides what is set in AG Grid. Setting `RowGroupDisplayType` at Layout level allows you to specify different behaviours for different Layouts **Example: Full Width Grouped Rows** Displaying full-width Grouped Rows - In this demo we create a **Full Width Group Rows** Layout with `RowGroupDisplayType`: `groupRows` - Accordingly, the Grouped Row takes the whole of the Row - and hides the aggregations we applied on 3 columns - The other Layout - **Single Grouped Rows** - has `RowGroupDisplayType`: `single` which allows the aggregations to be displayed - Switch Layouts in the Layout toolbar and compare how Grouped Rows look - Note that aggregations are configured on both Layouts but only visible on the multi layout ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Full Width Grouped Rows', initialState: { Dashboard: { PinnedToolbars: ['Layout'], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Full Width Grouped Rows', Layouts: [ { Name: 'Single Grouped Rows', RowGroupedColumns: ['language'], RowGroupDisplayType: 'groupRows', RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, TableAggregationColumns: [ {ColumnId: 'github_stars', AggFunc: 'sum'}, {ColumnId: 'open_issues_count', AggFunc: 'sum'}, {ColumnId: 'closed_issues_count', AggFunc: 'sum'}, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'open_issues_count', 'closed_issues_count', 'github_stars', 'github_watchers', 'open_pr_count', 'closed_pr_count', ], ColumnSorts: [{ColumnId: 'language', SortOrder: 'Asc'}], AutoSizeColumns: true, }, { Name: 'Full Width Grouped Rows', RowGroupedColumns: ['language'], RowGroupDisplayType: 'groupRows', RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, TableAggregationColumns: [ {ColumnId: 'github_stars', AggFunc: 'sum'}, {ColumnId: 'open_issues_count', AggFunc: 'sum'}, {ColumnId: 'closed_issues_count', AggFunc: 'sum'}, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'open_issues_count', 'closed_issues_count', 'github_stars', 'github_watchers', 'open_pr_count', 'closed_pr_count', ], ColumnSorts: [{ColumnId: 'language', SortOrder: 'Asc'}], AutoSizeColumns: true, }, ], }, }, }; ``` ## Displaying Content Three Modules support Row Grouping by rendering their content in Grouped Rows: | Module | Only Columns with Aggregation | | --------------------------------------------------------------------------- | :---------------------------: | | [Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) | ✅ | | [Styled Column](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md) | ✅ | | [Action Columns](https://www.adaptabletools.com/docs/handbook-action-column/index.md) | ❌ | ### Excluding Group Rows By default, Format Columns and Action Columns render in Grouped Rows (and in [Pivot Layouts](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md)). Styled Columns _can_ also render in Grouped Rows (depending on the Style - see below for full details). To hide any module's content from group rows, set `ExcludeGroupRows` to `true` on that object's `RowScope`. - The [`RowScope`](https://www.adaptabletools.com/docs/reference/rowscope.md) object also has `ExcludeDataRows`, `ExcludeSummaryRows`, and `ExcludeTotalRows` - These properties allow you to define a Format Column or Styled Column that appears **only** in Grouped Rows ### Format Columns Format Columns will be automatically rendered in any Grouped Row cell that contains an Aggregation. If this is not desired then set `ExcludeGroupRows` to `true` in the Format Column's `RowScope` property **Example: Grouped Rows: Format Columns** Using Format Columns in Grouped Rows - This example demonstrates adding Format Columns to Grouped Rows in AdapTable - We row-group on `Language` Column, set many Columns to have a `sum` Aggregation - We provide 3 sets of Format Columns each with different exclusion rules: - `Open PRs`and `Closed PRs` have a Fore Color of blue and **no exclusions** (so is rendered in whole column) - `Open Issues` and `Closed Issues` have a Fore Color of yellow **excludes** regular rows (so is only rendered in Grouped Rows) - `Github Stars` and `Github Watchers` have a Fore Color of red and **excludes** Grouped Rows (so is only rendered in leaf / data Rows) - Remove an Aggregation for a Column and note how **nothing** will appear in that Column's Grouped Rows ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Grouped Rows - Format Columns', initialState: { Dashboard: { ModuleButtons: ['FormatColumn', 'SettingsPanel'], Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Grouped Layout', Layouts: [ { Name: 'Grouped Layout', RowGroupedColumns: ['language'], RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'open_issues_count', AggFunc: 'sum', }, { ColumnId: 'closed_issues_count', AggFunc: 'sum', }, { ColumnId: 'open_pr_count', AggFunc: 'sum', }, { ColumnId: 'closed_pr_count', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'open_pr_count', 'closed_pr_count', 'open_issues_count', 'closed_issues_count', 'github_stars', 'github_watchers', 'week_issue_change', 'updated_at', 'created_at', ], ColumnSorts: [ { ColumnId: 'language', SortOrder: 'Asc', }, ], AutoSizeColumns: true, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-github_stars', Scope: { ColumnIds: ['github_stars', 'github_watchers'], }, Style: { ForeColor: 'Red', }, RowScope: { ExcludeGroupRows: true, }, }, { Name: 'formatColumn-open_issues_count', Scope: { ColumnIds: ['open_issues_count', 'closed_issues_count'], }, Style: { ForeColor: 'yellow', FontWeight: 'Bold', }, RowScope: { ExcludeDataRows: true, }, }, { Name: 'formatColumn-open_pr_count', Scope: { ColumnIds: ['open_pr_count', 'closed_pr_count'], }, Style: {ForeColor: 'LightBlue'}, }, ], }, }, }; ``` ### Styled Columns Most Styled Columns can render in Grouped Rows - in cells that contain an Aggregation. If the Layout is set to [Full With Grouped Rows](#full-width-group-rows), no Styled Columns are rendered (as there are no aggregations) Grouped Row visibility is set via the `RowScope` property in the [`StyledColumn`](https://www.adaptabletools.com/docs/reference/styledcolumn.md) object. Prior to [Version 23.0](https://www.adaptabletools.com/support/version-230-release-note) the `BadgeStyle` had its own `RowScope` property which has now been removed The actual Grouped Row behaviour varies depending on 2 factors: - the Styled Column Type - whether `RowScope` is explicitly set | Styled Column type | `RowScope` unset (default) | `RowScope` set | | ---------------------------------------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | **Badge** | Renders on Data, Group, Summary, and Total rows | Each `Exclude` flag controls that row kind | | **Gradient, Percent Bar, Icon, Bullet Chart, Rating, Range Bar** | Renders on Data, Summary, and Total rows — **not** on Group rows | Unset `Exclude` flags mean _include_; set `ExcludeGroupRows`: `true` to hide on groups | | **Sparkline** | Data (leaf) rows only | Group, Summary, Total always excluded | This means that if the `RowScope` property is omitted, only **Badge** styles will render on group rows by default Cells which exclude a Styled Column will still show Format Columns (if configured) **Example: Grouped Rows: Styled Columns** Badge, Gradient, and Percent Bar on Grouped Rows - This demo has a Grouped Row with several aggregations and different behaviour for the various Styled Columns provided: - **Badge** on `closed_issues_count` — no `RowScope` (default): badge on data and group rows - **Badge** on `open_pr_count` — `RowScope.ExcludeDataRows`: `true`: badge **only** on Grouped Rows - **Badge** on `closed_pr_count` — `RowScope.ExcludeGroupRows`: `true`: badge **only** on leaf rows - **Gradient** on `github_stars` — no `RowScope`: default excludes group rows (aggregated value shown as plain text) - **Percent Bar** on `open_issues_count` — `RowScope`: `{}` (explicit include): bar also drawn on Grouped Rows - Note: the [Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) on `open_pr_count` and `closed_pr_count` can be seen in the cells where badges are excluded ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Grouped Rows - Styled Columns', initialState: { Dashboard: { ModuleButtons: ['StyledColumn', 'SettingsPanel'], Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Grouped Layout', Layouts: [ { Name: 'Grouped Layout', RowGroupedColumns: ['language'], RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, TableAggregationColumns: [ {ColumnId: 'github_stars', AggFunc: 'sum'}, {ColumnId: 'open_issues_count', AggFunc: 'sum'}, {ColumnId: 'closed_issues_count', AggFunc: 'sum'}, {ColumnId: 'open_pr_count', AggFunc: 'sum'}, {ColumnId: 'closed_pr_count', AggFunc: 'sum'}, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'github_stars', 'github_watchers', 'week_issue_change', 'updated_at', 'created_at', ], ColumnSorts: [{ColumnId: 'language', SortOrder: 'Asc'}], AutoSizeColumns: true, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-open_pr_count', Scope: { ColumnIds: ['open_pr_count', 'closed_pr_count'], }, Style: {ForeColor: 'LightBlue'}, }, ], }, StyledColumn: { StyledColumns: [ { ColumnId: 'closed_issues_count', Name: 'closed_issues_count Badge', BadgeStyle: { Badges: [ { PillStyle: { BackColor: 'Brown', ForeColor: 'White', }, }, ], }, }, { ColumnId: 'open_pr_count', Name: 'open_pr_count Badge', RowScope: {ExcludeDataRows: true}, BadgeStyle: { Badges: [ { PillStyle: { BackColor: 'DarkGray', ForeColor: 'White', }, }, ], }, }, { ColumnId: 'closed_pr_count', Name: 'closed_pr_count Badge', RowScope: {ExcludeGroupRows: true}, BadgeStyle: { Badges: [ { PillStyle: { BackColor: 'DarkGray', ForeColor: 'White', }, }, ], }, }, { ColumnId: 'github_stars', Name: 'github_stars Gradient', GradientStyle: { CellRanges: [ { Min: 'Col-Min', Max: 'Col-Max', Color: 'DarkOrange', }, ], }, }, { ColumnId: 'open_issues_count', Name: 'open_issues_count Percent Bar', RowScope: {}, PercentBarStyle: { RangeValueType: 'Number', CellRanges: [ { Min: 'Col-Min', Max: 'Col-Max', Color: 'Green', }, ], BackColor: '#404040', }, }, ], }, }, }; ``` ### Action Columns Action Columns are automatically rendered in all Grouped Row cells. If this is not desired, then the `ExcludeGroupRows` option in the Action Column's `rowScope` property, can be used to exclude Grouped Rows from rending the Action Column. **Example: Row Grouping: Action Columns in Grouped Rows** Adding Action Columns in Grouped Rows created by Row Grouped Columns - This example demonstrates adding Action Columns to Grouped Rows in AdapTable; we again row-group on `Language` Column - We provide 2 Action Columns each with different exclusion rules: - `Change Theme` - has **no exclusions** (so is rendered in whole column) - `Add Star` **excludes** Grouped rows (so is only rendered in leaf / data Rows) ```ts import { ActionColumnButton, ActionColumnContext, AdaptableOptions, CellUpdateRequest, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Grouped Rows - Badge Styles', actionColumnOptions: { actionColumns: [ { columnId: 'add_star', friendlyName: 'Add Star', rowScope: { ExcludeGroupRows: true, }, actionColumnSettings: { suppressMenu: true, resizable: false, }, actionColumnButton: { label: 'Add Star', buttonStyle: { variant: 'outlined', tone: 'neutral', }, onClick: ( button: ActionColumnButton, context: ActionColumnContext ) => { const cellUpdateRequest: CellUpdateRequest = { columnId: 'github_stars', newValue: context.rowNode?.data.github_stars + 1, primaryKeyValue: context.primaryKeyValue, rowNode: context.rowNode, }; context.adaptableApi.gridApi.setCellValue(cellUpdateRequest); }, }, }, { columnId: 'change_theme', friendlyName: 'Theme', actionColumnButton: { label: 'Change Theme', buttonStyle: { variant: 'outlined', tone: 'neutral', }, onClick: ( button: ActionColumnButton, context: ActionColumnContext ) => { context.adaptableApi.themeApi.getCurrentTheme() == 'light' ? context.adaptableApi.themeApi.loadDarkTheme() : context.adaptableApi.themeApi.loadLightTheme(); }, }, }, ], }, initialState: { Dashboard: { ModuleButtons: ['SettingsPanel'], Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Grouped Layout', Layouts: [ { Name: 'Grouped Layout', RowGroupedColumns: ['language'], RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'open_issues_count', AggFunc: 'sum', }, { ColumnId: 'closed_issues_count', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'add_star', 'github_watchers', 'change_theme', 'open_issues_count', 'closed_issues_count', 'week_issue_change', 'updated_at', 'created_at', ], ColumnSorts: [ { ColumnId: 'language', SortOrder: 'Asc', }, ], AutoSizeColumns: true, }, ], }, FlashingCell: { FlashingCellDefinitions: [ { Name: 'Flashing_Cell_Any_Change', Rule: { BooleanExpression: 'ANY_CHANGE()', }, Scope: { All: true, }, }, ], }, }, }; ``` ## Selecting Grouped Rows By default, selecting a Grouped Row will select just that row only, and not any of the Group's leaf Rows. However it is possible to change this behaviour to select all leaf rows or filtered leaf rows. This is done via the `GroupSelectMode` property in the `RowSelection` section of a Layout. See [Configuring Row Selection In Layouts](https://www.adaptabletools.com/docs/handbook-layouts-table-row-selection/index.md) for more information --- # Row Grouping - Sorting Canonical page: https://www.adaptabletools.com/docs/handbook-grouping-rows-sorting - AdapTable enables the Row Grouped Column to be sorted - There is an order of evaluation concerning the different sorting possibilities AdapTable will apply sorting on the column being Row-Grouped. There are many different ways in AdapTable and AG Grid that sorting can be applied, which are evaluated by AdapTable using the following priority: 1. an active AdapTable [Custom Sort](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md) 2. a `ColDef` Comparator created in AG Grid Column Defs 3. the current Layout [Column Sort](https://www.adaptabletools.com/docs/handbook-layouts-table-sorting/index.md) 4. AG Grid's default sort mechanism (typically alphanumerically) **Example: Row Grouping: Sorting** Sorting Row Groups in AdapTable - In this example we provide 4 Layouts to demonstrate different elements of sorting Row Groups: - The `Custom Sort Layout` is grouped by `Language`. We also provide a Custom Sort for the `Language` Column and we sort by it. Accordingly, the Custom Sort is applied in the Layout. - The `AG Grid Comparator Layout` is grouped by `Issue Change`, which we also sort by it (in ascending order) This column has an AG Grid comparator, and so this sort is applied in the Layout. - The `Column Sort Layout` is grouped by `License`, which we also sort by it (in descending order). Accordingly, this sort is applied in the Layout. - The `No Sort Layout` is grouped by `License`, but we have not provided any sorting, so no sorting is applied to the Layout - Click the header in the `No Sort Layout` to sort the Row Grouped Column - Note how the Row Grouped Column is now sorted in default (ie alphabetical) order ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Row Grouping: Sorting', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, CustomSort: { CustomSorts: [ { Name: 'customSort-language', ColumnId: 'language', SortedValues: ['TypeScript', 'HTML', 'JavaScript'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Custom Sort Layout', Layouts: [ { Name: 'Custom Sort Layout', RowGroupedColumns: ['language'], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSorts: [ { ColumnId: 'language', SortOrder: 'Asc', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'license', 'github_watchers', 'updated_at', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'AG Grid Comparator Layout', RowGroupedColumns: ['week_issue_change'], ColumnSorts: [ { ColumnId: 'week_issue_change', SortOrder: 'Asc', }, ], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'Column Sort Layout', RowGroupedColumns: ['license'], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSorts: [ { ColumnId: 'license', SortOrder: 'Desc', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', ], AutoSizeColumns: true, }, { Name: 'No Sort Layout', RowGroupedColumns: ['license'], TableAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'updated_at', 'description', 'created_at', ], 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, }, autoGroupColumnDef: { floatingFilter: true, filter: 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 {ColDef} from 'ag-grid-enterprise'; import {WebFramework} from 'rowData'; export const columnDefs: ColDef[] = [ { field: 'name', cellDataType: 'text', sortable: true, }, { field: 'language', cellDataType: 'text', enablePivot: true, enableRowGroup: true, }, { field: 'github_stars', headerName: 'GitHub Stars', cellDataType: 'number', type: 'github', enableValue: true, }, { field: 'github_watchers', headerName: 'GitHub Watchers', cellDataType: 'number', type: 'github', enableValue: true, }, { field: 'license', cellDataType: 'text', editable: false, enablePivot: true, enableRowGroup: true, }, { field: 'week_issue_change', headerName: 'Issue Change', cellDataType: 'number', enableValue: true, comparator: numericComparator, }, { 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', type: 'issue-pr', enableValue: true, }, { field: 'closed_issues_count', headerName: 'Closed Issues', cellDataType: 'number', type: 'issue-pr', enableValue: true, }, { field: 'open_pr_count', headerName: 'Open PRs', cellDataType: 'number', type: 'issue-pr', enableValue: true, }, { field: 'closed_pr_count', headerName: 'Closed PRs', cellDataType: 'number', type: 'issue-pr', 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, }, ]; function numericComparator(valueA: any, valueB: any) { return Math.abs(valueB) - Math.abs(valueA); } ``` --- # Highlighting and Jumping Canonical page: https://www.adaptabletools.com/docs/handbook-highlighting-jumping - AdapTable provides methods in Grid API which allows the user to highlight given cells, columns and rows - The Highlight uses the AdapTable Style object - AdapTable also provides Grid API methods which allows the user to jump to given cells, columns and rows The [`Grid API`](https://www.adaptabletools.com/docs/reference/gridapi.md) section of AdapTable API includes many useful Grid related functions. These include functions which facilitate 2 useful, often connected, Grid-related activities: - **highlighting** cells and rows - **jumping** to columns, rows and cells ## Highlighting There are a number of Grid API functions which facilitate cell, row and column highlighting: - `highlightCell` - `unHighlightCell` - `unHighlightAllCells` - `highlightColumn` - `unHighlightColumn` - `unHighlightAllColumns` - `highlightRow` - `highlightRows` - `unHighlightRow` - `unHighlightRows` - `unHighlightAllRows` **Example: Highlighting Cells and Rows** Using Grid API to highlight cells and rows in AdapTable - This demo provides examples of highlighting and unhlighting using the [`Grid API`](https://www.adaptabletools.com/docs/reference/gridapi.md) (using 3 Custom Toolbar Buttons): - First button calls `highlightCell` function to highlight the `Name` cell for _ember.js_ row with a white fore colour and purple back colour (with a timeout of 5 seconds) - Second button calls `highlightRow` function to highlight the whle row for _Solid_ with a gray fore colour and brown back colour - Third button calls `unHighlightRow` function for _Solid_ row which clears the highlight - Fourth button calls `HighlightColumn` function for for Github Stars column (with timeout of 3 seconds) ```ts import { AdaptableButton, AdaptableOptions, CellHighlightInfo, CustomToolbarButtonContext, RowHighlightInfo, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Highlighting API', dashboardOptions: { customToolbars: [ { name: 'ButtonToolbar', title: 'Buttons', toolbarButtons: [ { label: 'Highlight "ember.js" (5 secs)', onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { // Highlight a cell for 5 seconds const cellHighlightInfo: CellHighlightInfo = { columnId: 'name', primaryKeyValue: 1801829, timeout: 5000, highlightStyle: { BackColor: 'Purple', ForeColor: 'White', }, }; context.adaptableApi.gridApi.highlightCell(cellHighlightInfo); }, buttonStyle: { tone: 'info', variant: 'text', }, }, { label: 'Highlight "solid" Row', onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { const rowHighlightInfo: RowHighlightInfo = { primaryKeyValue: 130884470, highlightStyle: { BackColor: 'Brown', ForeColor: 'Gray', }, }; context.adaptableApi.gridApi.highlightRow(rowHighlightInfo); }, buttonStyle: { tone: 'success', variant: 'text', }, }, { label: 'Unighlight "solid" Row', onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { context.adaptableApi.gridApi.unHighlightRow(130884470); }, buttonStyle: { tone: 'warning', variant: 'text', }, }, { label: 'Highlight Github Watchers Column (3 secs)', onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { context.adaptableApi.gridApi.highlightColumn({ columnId: 'github_watchers', highlightStyle: { BackColor: 'Brown', ForeColor: 'Gray', }, timeout: 3000, }); }, buttonStyle: { tone: 'error', variant: 'text', }, }, ], }, ], }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['ButtonToolbar'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'license', 'created_at', 'has_wiki', 'github_watchers', 'updated_at', 'pushed_at', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ### Style Each highlight function receives a commonly used [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) object which contains numerous properties, allowing for full control over how the highlight looks. ### Timeout The highlight functions can be provided with a timeout specifying how long the cell or row will remain highlighted. ### Highlight Info Objects and Styles The highlight functions receive a [`CellHighlightInfo`](https://www.adaptabletools.com/docs/reference/cellhighlightinfo.md) or a [`RowHighlightInfo`](https://www.adaptabletools.com/docs/reference/rowhighlightinfo.md) object as needed. Both provide details of the Cell / Row to be highlighted and the [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) to use The `CellHighlightInfo` object is defined as follows: | Property | Type | Description | | --- | --- | --- | | [columnId](https://www.adaptabletools.com/docs/reference/cellhighlightinfo.md#columnid) | `string` | Id of Column containing Cell | | [highlightStyle](https://www.adaptabletools.com/docs/reference/cellhighlightinfo.md#highlightstyle) | [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) | Adaptable Style to use in the Cell Highlight | | [primaryKeyValue](https://www.adaptabletools.com/docs/reference/cellhighlightinfo.md#primarykeyvalue) | `any` | Primary Key Value of row containing Cell | | [timeout](https://www.adaptabletools.com/docs/reference/cellhighlightinfo.md#timeout) | `number` | Time after which Cell should be unhighlighted | The `RowHighlightInfo` is defined as follows: | Property | Type | Description | | --- | --- | --- | | [highlightStyle](https://www.adaptabletools.com/docs/reference/rowhighlightinfo.md#highlightstyle) | [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) | Highlight style | | [primaryKeyValue](https://www.adaptabletools.com/docs/reference/rowhighlightinfo.md#primarykeyvalue) | `any` | Primary key value for the row to be highlighted | | [timeout](https://www.adaptabletools.com/docs/reference/rowhighlightinfo.md#timeout) | `number` | Timeout after which Row should be unhighlighted | Both objects contain a `highlightStyle` property of type [`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) which has these 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 | --- ## Jumping The Grid API section of AdapTable API contains 3 functions that enable moving the focus in the Grid to specific cells, rows or columns: - `jumpToRow` - `jumpToColumn` - `jumpToCell` **Example: Jumping to Cells and Rows** Using Grid API to move focus to given Cells, Rows & Columns - This demo provides examples of "jumping" using the [`Grid API`](https://www.adaptabletools.com/docs/reference/gridapi.md) - We provide 3 Custom Toolbar Buttons which each call a jump-related function: - First button calls `jumpToCell` function to jump to `Created At` in the _Quasar_ row (the last row in the grid) - Second button calls `jumpToRow` function to jump to _Angular_ row (2nd from top) - Third button calls `jumpToColumn` function to jump to the `Issue Change` column (at the far end of the grid) - Additionally we provide a [Custom Context Menu Item](https://www.adaptabletools.com/docs/ui-context-menu-custom-items/index.md) that displays all Columns in the Grid, and AdapTable will jump to the Column selected ```ts import { AdaptableButton, AdaptableColumn, AdaptableOptions, CellHighlightInfo, CustomContextMenuContext, CustomToolbarButtonContext, RowHighlightInfo, UserContextMenuItem, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Jumping Functions', contextMenuOptions: { customContextMenu: (context: CustomContextMenuContext) => { const { defaultAgGridMenuStructure, defaultAdaptableMenuStructure, adaptableApi, } = context; const columnNameMenuItems: UserContextMenuItem[] = adaptableApi.columnApi .getVisibleColumns() .map((c: AdaptableColumn) => { return { menuType: 'User', label: c.friendlyName, onClick: () => { adaptableApi.gridApi.jumpToColumn(c.columnId); }, }; }); const jumpToColumnMenuItem: UserContextMenuItem = { menuType: 'User', label: 'Jump To', icon: { name: 'greater-than', }, subMenuItems: columnNameMenuItems, }; return [ jumpToColumnMenuItem, ...defaultAgGridMenuStructure, '-', ...defaultAdaptableMenuStructure, ]; }, }, dashboardOptions: { customToolbars: [ { name: 'ButtonToolbar', title: 'Buttons', toolbarButtons: [ { label: 'Jump to "Qasar" / Created At', onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { context.adaptableApi.gridApi.jumpToCell(43695474, 'created_at'); }, buttonStyle: { tone: 'info', variant: 'text', }, }, { label: 'Jump to "Angular" Row', onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { context.adaptableApi.gridApi.jumpToRow(24195339); }, buttonStyle: { tone: 'success', variant: 'text', }, }, { label: 'Jump to "Issue Change" Column', onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { context.adaptableApi.gridApi.jumpToColumn('week_issue_change'); }, buttonStyle: { tone: 'warning', variant: 'text', }, }, ], }, ], }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['ButtonToolbar'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'license', 'created_at', 'has_wiki', 'github_watchers', 'updated_at', 'pushed_at', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` --- # Importing Data into AdapTable Canonical page: https://www.adaptabletools.com/docs/handbook-importing - Data Import allows run-time users to update data in AdapTable in a single workflow - The imported data can update existing rows, provide new rows or populate the entire grid - The Data Import wizard facilitates the import process via a series of steps, including Column matching - Validation is also available to ensure that the data being imported meets custom business rules AdapTable enables data to be imported into AG Grid at run-time. This data can be imported in 3 forms: - JSON file - CSV file - Text (i.e. copy and paste) The data can consist of either updates to existing rows in the Grid, or details of new rows. The AdapTable-provided handlers for CSV and JSON files can be replaced, and / or extended, by [custom file handlers](https://www.adaptabletools.com/docs/handbook-importing-configuring/index.md) ## Updating Data The most common use case is when the data being imported overrides that which is already in the Grid. **Example: Data Import - Update Rows** Updating Data using Data Import - This example shows how to use Data Import to **update existing** rows in AdapTable - Download either updateframeworks.json or updateframeworks.csv files - which both contain (the same) changes to the first 2 rows (react and angular) - Then upload that file in the Data Import wizard - We have added [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) to the grid (and increased duration to 3 seconds) so you can see the changes to the first 2 rows - Click the Import Data button in the Dashboard (or use a menu option) to open the Wizard - In the first step load one of the 2 files and click "Import" ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Data Import - Update Rows', initialState: { Dashboard: { ModuleButtons: ['DataImport'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, FlashingCell: { FlashingCellDefinitions: [ { Name: 'Flashing_Cell_Any_Change', Scope: { All: true, }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, FlashDuration: 3000, }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'license', 'github_watchers', 'has_projects', ], AutoSizeColumns: true, }, ], }, }, }; ``` ## Adding Whole Rows The imported data can also consist of new rows which AdapTable will add to the grid. It is possible to import data which contains both new rows and updates to existing rows **Example: Data Import - Add Rows** Adding New Rows using Data Import - This example shows how to use Data Import to **add new** rows into AdapTable - Download either addframeworks.json or addframeworks.csv files - which both contain (the same) 2 rows to add - Then upload that file in the Data Import wizard - We have added a `ROW_ADDED` [Row Change Alert](https://www.adaptabletools.com/docs/handbook-alerting-row-change/index.md) with a highlight row behaviour to show the rows that were added - Click the Import Data button in the Dashboard (or use a menu option) to open the Wizard - In the first step load one of the 2 files and click "Import" ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Data Import - Add Rows', initialState: { Dashboard: { ModuleButtons: ['DataImport'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Alert: { AlertDefinitions: [ { Name: 'alert-row-added', Rule: { ObservableExpression: 'ROW_ADDED()', }, MessageType: 'Success', Scope: { All: true, }, AlertProperties: { DisplayNotification: false, HighlightRow: { BackColor: 'Purple', ForeColor: 'White', }, }, }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'license', 'github_watchers', 'has_projects', ], 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('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: '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: 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: -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: 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').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, }, ]; ``` ## Importing All Data Data Import can also be used to populate an empty Grid with a full set of data. **Example: Data Import - Adding all data** Adding All Data using Data Import - This example shows how to use Data Import to **all data** rows into AdapTable - the grid opens with no data provided - Download either allframeworks.json or allframeworks.csv files - which both contain the same data to add, and upload the file in the Data Import wizard - Note: the Grid is fully populated including 3 [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) which are evaluated using the imported data - Click the Import Data button in the Dashboard (or use a menu option) to open the Wizard - In the first step load one of the 2 files and click "Import" ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Data Import - Import All Data', initialState: { Dashboard: { ModuleButtons: ['DataImport'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'license', 'github_watchers', 'has_projects', 'open_issues', 'closed_issues', 'open_prs', 'closed_prs', 'subscribersRatio', 'open-total-issue-ratio', 'open-total-pr-ratio', ], 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: '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', }, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-subscribersRatio', Scope: { ColumnIds: [ 'subscribersRatio', 'open-total-issue-ratio', 'open-total-pr-ratio', ], }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { FractionDigits: 2, }, }, }, ], }, }, }; ``` ```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: [], 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: 'name', cellDataType: 'text', sortable: true, }, { field: 'language', cellDataType: 'text', enablePivot: true, enableRowGroup: true, }, { field: 'github_stars', headerName: 'GitHub Stars', type: 'github', cellDataType: 'number', enableValue: true, }, { field: 'github_watchers', headerName: 'GitHub Watchers', type: 'github', cellDataType: 'number', enableValue: true, }, { field: 'license', cellDataType: 'text', editable: false, enablePivot: true, enableRowGroup: true, }, { field: 'week_issue_change', headerName: 'Issue Change', cellDataType: 'number', enableValue: true, }, { field: 'has_wiki', headerName: 'Has Wiki', cellDataType: 'boolean', enablePivot: true, enableRowGroup: true, }, { field: 'description', cellDataType: 'text', sortable: false, }, { field: 'open_issues_count', headerName: 'Open Issues', type: 'issue-pr', cellDataType: 'number', enableValue: true, }, { field: 'closed_issues_count', headerName: 'Closed Issues', type: 'issue-pr', cellDataType: 'number', enableValue: true, }, { field: 'open_pr_count', headerName: 'Open PRs', type: 'issue-pr', cellDataType: 'number', enableValue: true, }, { field: 'closed_pr_count', headerName: 'Closed PRs', type: 'issue-pr', 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, }, ]; ``` ## Column Matching The Import Data wizard attempts to match all the columns in the inputted data against those in the Grid's Column definitions. This is done by checking the column in the header of the input file against an existing ColumnId or FriendlyName. - The logic is that first AdapTable will try to find a Column where the `columnId` matches that in the input source - If nothing is found, then it will try to match using a Column `friendlyName` (aka the Header) If there are no matches AdapTable will display a dropdown with a list of all the current columns so the user can pick the correct one. **Example: Data Import - Matching Columns** Data Import with Column Matching - This example shows how the Data Import will try to match Columns automatically, and allow the user to provide those which cannot be matched - Download either the columnmatchingframeworks.json or the columnmatchingframeworks.csv file - Both files contain the same 2 rows to update as in the Updating Rows demo but with some columns in the import file **not** using the columnId: - Language and Licence are both Friendly Names / Headers - Stars and Watchers dont match either Column Id or Friendly Name - In all 4 cases the Columns section of the Import Data wizard asks the user to supply the relevant column - Click the Import Data button in the Dashboard (or use a menu option) to open the Wizard - In the first step load one of the 2 files and click "Import" - In the Columns step of the Wizard, supply the names of the columns that could not be matched automatically ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Data Import - Column Matching', initialState: { Dashboard: { ModuleButtons: ['DataImport'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, FlashingCell: { FlashingCellDefinitions: [ { Name: 'Flashing_Cell_Any_Change', Scope: { All: true, }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, FlashDuration: 3000, }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'license', 'github_watchers', 'has_projects', ], AutoSizeColumns: true, }, ], }, }, }; ``` ## Validating Import Data The data file can be validated before it is imported to make sure that it fits with business requirements. This is separate to any [Data Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-data-change/index.md) which fire **after** the data has been imported into the Grid Data Validation is done using the `validate` function property in [Data Import Options](https://www.adaptabletools.com/docs/handbook-importing-technical-reference/index.md). ### `validate` Function to validate the Imported Data [`DataImportValidationError[]`](https://www.adaptabletools.com/docs/reference/dataimportvalidationerror.md) Use this function to validate the data being imported into AG Grid via the Data Import wizard. It allows for bad data to be rejected before it gets added to the Grid. The function receives a [`DataImportValidateContext`](https://www.adaptabletools.com/docs/reference/dataimportvalidatecontext.md) and returns a [`DataImportValidationError`](https://www.adaptabletools.com/docs/reference/dataimportvalidationerror.md) array. The [`DataImportValidateContext`](https://www.adaptabletools.com/docs/reference/dataimportvalidatecontext.md) object contains just the row data being imported: | Property | Type | Description | | --- | --- | --- | | [rowData](https://www.adaptabletools.com/docs/reference/dataimportvalidatecontext.md#rowdata) | `T` | Imported Row Data | | [adaptableContext](https://www.adaptabletools.com/docs/reference/dataimportvalidatecontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | The [`DataImportValidationError`](https://www.adaptabletools.com/docs/reference/dataimportvalidationerror.md) object includes the Column where validation fails and an error message: | Property | Type | Description | | --- | --- | --- | | [columnId](https://www.adaptabletools.com/docs/reference/dataimportvalidationerror.md#columnid) | `string` | Column which contains the Error | | [error](https://www.adaptabletools.com/docs/reference/dataimportvalidationerror.md#error) | `string` | The validatoin error text | ```ts {3} const adaptableOptions: AdaptableOptions = { dataImportOptions = { validate: (context: DataImportValidateContext) => { const rowData = context.rowData; return rowData.license !== 'MIT License' && rowData.license !== 'Other' ? [ { columnId: 'license', error: 'License must be "MIT License" or "Other"', }, ] : []; }, }, }; ``` **Example: Data Import - Validation** Validating Data in Data Import - This example shows how to **validate** the data in Data Import - Download either updateframeworks.json or updateframeworks.csv files - which both contain (the same) changes to the first 2 rows (react and angular) - But this time we have added a Validation rule that the `License` must be either _MIT License_ or _Other_ - Then upload that file in the Data Import wizard ### Expand to the validate function ```ts dataImportOptions: { validate: (context: DataImportValidateContext) => { const rowData = context.rowData; return rowData.license !== 'MIT License' && rowData.license !== 'Other' ? [ { columnId: 'license', error: 'License must be "MIT License" or "Other"', }, ] : []; }, }, ``` - Click the Import Data button in the Dashboard (or use a menu option) to open the Wizard - In the first step load one of the 2 files and click "Import" - Go to the Validation step and note that the License column contains an error in each row - Change one of the values to "Other" and the other "MIT License" and note that this passes validation and you are able to import ```ts import { AdaptableOptions, DataImportValidateContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Data Import - Validating', dataImportOptions: { validate: (context: DataImportValidateContext) => { const rowData = context.rowData; return rowData.license !== 'MIT License' && rowData.license !== 'Other' ? [ { columnId: 'license', error: 'License must be "MIT License" or "Other"', }, ] : []; }, }, initialState: { Dashboard: { ModuleButtons: ['DataImport'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Export'], }, ], }, FlashingCell: { FlashingCellDefinitions: [ { Name: 'Flashing_Cell_Any_Change', Scope: { All: true, }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, FlashDuration: 3000, }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'license', 'github_watchers', 'has_projects', ], AutoSizeColumns: true, }, ], }, }, }; ``` --- # Configuring Data Import Canonical page: https://www.adaptabletools.com/docs/handbook-importing-configuring - AdapTable provides 2 file handlers - CSV and JSON - for Data Import - These can be supplemented or replaced by custom file handlers provided by developers ## Custom File Handlers AdapTable ships with 2 File Handlers for Data Import: CSV and JSON. However developers can provide custom file handlers where required. These can either override an AdapTable-shipped file handler, or handle a different file type This is done via the `fileHandlers` property in [Data Import Options](https://www.adaptabletools.com/docs/handbook-importing-technical-reference/index.md). ### `fileHandlers` Custom File Handlers to use for Data Import [`DataImportFileHandler`](https://www.adaptabletools.com/docs/reference/dataimportfilehandler.md) Allows to developers to provide custom File Handlers for Data Import where the shipped File Handlers are insufficient. The custom File Handler can either: - replace one of the File Handlers provided by AdapTable (CSV or JSON) - handle a different type of File The [`DataImportFileHandler`](https://www.adaptabletools.com/docs/reference/dataimportfilehandler.md) is defined as follows: | Property | Type | Description | | --- | --- | --- | | [fileExtension](https://www.adaptabletools.com/docs/reference/dataimportfilehandler.md#fileextension) | `string` | Name of File Extension | | [handleFile](https://www.adaptabletools.com/docs/reference/dataimportfilehandler.md#handlefile) | `(file: File) => Promise` | Async function which handles the import returning a Data Record | The `handleFile` property returns the data in the form of ` Record` The File Handlers are typically just referenced in Data Import Options: ```ts {2} dataImportOptions: { fileHandlers: [csvFileHandler], }, ``` and defined elsewhere: ```ts {1} const csvFileHandler: DataImportFileHandler> = { fileExtension: '.csv', handleFile: (file: File) => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = event => { const content = event.target?.result as string; resolve(parseCSV(content)); }; reader.readAsText(file); }); }, }; export const parseCSV = (content: string): Record[] => { const SEPARATOR = '|'; const lines = content.split('\n'); const headers = lines[0].split(SEPARATOR); const data = []; if (lines.length <= 1) { return []; } for (let i = 1; i < lines.length; i++) { const values = lines[i].split(SEPARATOR); if (values.length === headers.length) { const item: Record = {}; for (let j = 0; j < headers.length; j++) { const value = values[j]; // Any string that looks like a number it is converted to number item[headers[j]] = value === '' || isNaN(Number(value)) ? value : Number(value); } data.push(item); } } return data; }; ``` **Example: Data Import - Custom CSV File Handler** Custom file handlers. - This example overrides the CSV file handler provided by AdapTable with a custom file handler, that parses CSV using a different (|) delimiter - Download the updateframeworks-pipe.csv file, and then upload it in the Data Import wizard, and it will be parsed by the custom file handler - We have added [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) to the grid (and increased duration to 3 seconds) so you can see the changes to the first 2 rows ```ts import { AdaptableOptions, DataImportFileHandler, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; /** * Custom parser that uses | for separator */ export const parseCSV = (content: string): Record[] => { const SEPARATOR = '|'; const lines = content.split('\n'); const headers = lines[0].split(SEPARATOR); const data = []; if (lines.length <= 1) { return []; } for (let i = 1; i < lines.length; i++) { const values = lines[i].split(SEPARATOR); if (values.length === headers.length) { const item: Record = {}; for (let j = 0; j < headers.length; j++) { const value = values[j]; // Any string that looks like a number is converted to number // Note: this converts 00012345 to 12345 or a value with potential scientific notation to a number item[headers[j]] = value === '' || isNaN(Number(value)) ? value : Number(value); } data.push(item); } } return data; }; // Custom CSV File Handler const csvFileHandler: DataImportFileHandler> = { fileExtension: '.csv', handleFile: (file: File) => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = event => { const content = event.target?.result as string; resolve(parseCSV(content)); }; reader.readAsText(file); }); }, }; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Custom CSV File Handler', dataImportOptions: { fileHandlers: [csvFileHandler], }, initialState: { Dashboard: { ModuleButtons: ['DataImport'], }, FlashingCell: { FlashingCellDefinitions: [ { Name: 'Flashing_Cell_Any_Change', Scope: { All: true, }, Rule: { BooleanExpression: 'ANY_CHANGE()', }, FlashDuration: 3000, }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'license', 'github_watchers', 'has_projects', ], AutoSizeColumns: true, }, ], }, }, }; ``` --- # Import Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-importing-technical-reference - Importing is set through Options - The Data Import API contains functions to manage exporting and reports programmatically - Import Event - There is no Initial Adaptable State associated with Data Import ------------------- ## Data Import Options The [`Data Import Options`](https://www.adaptabletools.com/docs/reference/dataimportoptions.md) section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) contains these properties: | Property | Type | Description | | --- | --- | --- | | [fileHandlers](https://www.adaptabletools.com/docs/reference/dataimportoptions.md#filehandlers) | [`DataImportFileHandler`](https://www.adaptabletools.com/docs/reference/dataimportfilehandler.md)`[]` | Custom File Handlers to use for Data Import | | [handleImportedData](https://www.adaptabletools.com/docs/reference/dataimportoptions.md#handleimporteddata) | `(context: `[`HandleImportedDataContext`](https://www.adaptabletools.com/docs/reference/handleimporteddatacontext.md)`) => Promise` | Function to handle the Imported Data and apply it to the Grid. If not provided then the Data will be applied to the Grid automatically. | | [textHandler](https://www.adaptabletools.com/docs/reference/dataimportoptions.md#texthandler) | `(text: string) => T[] \| Promise` | Handles Importing Data using text | | [validate](https://www.adaptabletools.com/docs/reference/dataimportoptions.md#validate) | `(context: `[`DataImportValidateContext`](https://www.adaptabletools.com/docs/reference/dataimportvalidatecontext.md)`) => `[`DataImportValidationError`](https://www.adaptabletools.com/docs/reference/dataimportvalidationerror.md)`[] \| undefined` | Function to validate the Imported Data | | [_getPrimaryKeyValue](https://www.adaptabletools.com/docs/reference/dataimportoptions.md#_getprimarykeyvalue) | `(context: `[`GetPrimaryKeyValueContext`](https://www.adaptabletools.com/docs/reference/getprimarykeyvaluecontext.md)`) => string \| number` | Function to get the Primary Key value for a data row (defaults to value of the primaryKey column) | | [_preprocessRowData](https://www.adaptabletools.com/docs/reference/dataimportoptions.md#_preprocessrowdata) | `(context: `[`PreprocessRowDataContext`](https://www.adaptabletools.com/docs/reference/preprocessrowdatacontext.md)`) => Record` | Function to pre-process the data before it is imported | ------- ## Data Import API The [`Data Import API`](https://www.adaptabletools.com/docs/reference/dataimportapi.md) section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) contains just one function which starts the Data Import Wizard: | Method | Returns | Description | | --- | --- | --- | | [openImportWizard()](https://www.adaptabletools.com/docs/reference/dataimportapi.md#openimportwizard) | `void` | Opens the Data Import Wizard | ------- ## Data Imported Event The Data Imported Event is published whenever data has been imported. ### DataImportedInfo The [`DataImportedInfo`](https://www.adaptabletools.com/docs/reference/dataimportedinfo.md) object returned by the Event contains details of the rows which have been added and / or updated by the Import. | Property | Type | Description | | --- | --- | --- | | [addedRows](https://www.adaptabletools.com/docs/reference/dataimportedinfo.md#addedrows) | `IRowNode[]` | Rows that were added | | [importData](https://www.adaptabletools.com/docs/reference/dataimportedinfo.md#importdata) | `any[]` | Raw data that was imported | | [updatedRows](https://www.adaptabletools.com/docs/reference/dataimportedinfo.md#updatedrows) | `IRowNode[]` | Rows that were updated | | [adaptableContext](https://www.adaptabletools.com/docs/reference/dataimportedinfo.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('DataImported', (eventInfo: DataImportedInfo) => { // do something with the info }); ``` --- # Layouts Canonical page: https://www.adaptabletools.com/docs/handbook-layouts - AdapTable uses Layouts to manage sets of **columns** and column-related information - At least **one Layout must be provided** in Initial Adaptable State - Layouts are designed to enable users easily to switch between different column setups in their grid - Layouts typically contain column visibility and order information but can also include details about column: - sorting - row grouping and aggregations - column and grid filters - size / widths - pinning - Users can create 2 types of Layouts: - Table Layouts - standard rows and columns - Pivot Layouts - displayed when AG Grid is in Pivot Mode and showing pivoted data - Object Tags can be leveraged to extend Layouts by associating some Adaptable Objects with a given Layout Layouts are the primary way in AdapTable to manage Columns and Column-related info. They allow users to switch quickly between multiple, different, named, column set-ups in AG Grid. - [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) and [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) manage which Rows are displayed in AG Grid - Layouts specify which Columns are displayed AdapTable updates Layouts automatically in response to changes being made in AG Grid. - AdapTable requires there is always a "Current Layout" which defines (and saves) the current Column setup - Likewise AdapTable mandates that at least **one Layout to be defined** in [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md). Layouts include multiple column-related properties including row grouping, aggregations, pinning, widths etc By default, Layouts do not include styling or formatting information, i.e. all styles are available to all Layouts. However this can be achieved, if needed, by using [Extended Layouts](https://www.adaptabletools.com/docs/handbook-layouts-extending/index.md) which can include Styles and other objects ## Table & Pivot Layouts AdapTable provides 2 types of Layouts: - **[Table Layouts](https://www.adaptabletools.com/docs/handbook-layouts-table/index.md)** - used when accessing AG Grid in "normal" column mode - **[Pivot Layouts](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md)** - opens AG Grid in pivot mode displaying pivot, row-grouping and aggregation columns **Example: Basic Layout** Using Layouts in AdapTable - This example contains 3 Layouts: - `Standard Layout` - a Table Layout containing a list of Columns - `Grouped Layout` - a Table Layout which is [Row Grouped](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md) by the *Language* Column and contains 2 Aggregations - `Pivot Layout` - a Pivot Layout with Grouping, Pivoting and Aggregations - Switch between the 3 Layouts in the Dashboard (or Status Bar) - Click the Layout button in the Dashboard to open the Layout Wizard - Create a new Layout and choose which columns you would like to see ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Basic Layout', initialState: { Dashboard: { ModuleButtons: ['Layout', 'SettingsPanel'], PinnedToolbars: ['Layout'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'name', 'language', 'github_stars', 'license', 'created_at', 'has_wiki', 'updated_at', 'pushed_at', 'github_watchers', 'description', 'open_issues_count', 'closed_issues_count', 'open_pr_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Standard Layout', AutoSizeColumns: true, }, { TableColumns: [ 'name', 'license', 'open_issues_count', 'week_issue_change', ], TableAggregationColumns: [ { ColumnId: 'open_issues_count', AggFunc: 'sum', }, { ColumnId: 'week_issue_change', AggFunc: 'max', }, ], Name: 'Grouped Layout', RowGroupedColumns: ['language'], }, { Name: 'Pivot Layout', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'count', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, ], }, }, }; ``` ## Layout Contents A [Layout](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) contains a number of important column-related properties. The Columns in the Layout can include "Special Columns" - i.e. [Calculated](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md), [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 contents of Table and Pivot Layouts are fairly similar, with just a few differences: | Item | Table Layout | Pivot Layout | | -------------------------- | :----------: | :----------: | | Name | ✅ | ✅ | | Table Columns | ✅ | ❌ | | Pivot Columns | ❌ | ✅ | | Column Visibility | ✅ | ✅ | | Column Sizing | ✅ | ✅ | | Column Sorts | ✅ | ✅ | | Column Pinning | ✅ | ✅ | | Row Groups | ✅ | ✅ | | Expanded Row Group Info | ✅ | ✅ | | Aggregations | ✅ | ✅ | | Row Selection | ✅ | ✅ | | Column Filters | ✅ | ✅ | | Grid Filter | ✅ | ✅ | | Expanded Column Group Info | ✅ | ✅ | | Row Summaries | ✅ | ❌ | | Total Rows | ✅ | ✅ | | Total Columns | ❌ | ✅ | | SuppressAggFuncInHeader | ✅ | ✅ | | Auto Size Columns | ✅ | ✅ | | Tags & MetaData | ✅ | ✅ | See [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) for step by step instructions in defining the 2 types of Layouts ### Upgrading to Layouts in AdapTable 20 and 21 In AdapTable [v.20](https://www.adaptabletools.com/support/version-200-release-note) Layouts were upgraded significantly. This was then enhanced with Column Sizing (in [AdapTable 21](https://www.adaptabletools.com/support/version-210-release-note)) and Row Selection (in [AdapTable 22.1](https://www.adaptabletools.com/support/version-221-release-note)). The previous `Layout` object was replaced by 2 new objects ([`TableLayout`](https://www.adaptabletools.com/docs/reference/tablelayout.md) and [`PivotLayout`](https://www.adaptabletools.com/docs/reference/pivotlayout.md)) and many properties were renamed and significantly enhanced as follows: | Old Layout | New Layout | Type | Notes | | ------------------------- | ------------------------- | ----- | ----------------------------------------------------------------------------------------------------------------------- | | `EnablePivot` | n/a | n/a | Users now create Table **or** Pivot Layouts | | `Name` | `Name` | Both | Unchanged - still mandatory | | `Columns` | `TableColumns` | Table | Mandatory | | `PivotColumns` | `PivotColumns` | Pivot | Mandatory (provide empty array if none) | | `ColumnWidthMap` | `ColumnSizing` | Both | Now [`ColumnSizingMap`](https://www.adaptabletools.com/docs/reference/columnsizingmap.md) object (in v.21 only) | | `ColumnSorts` | `ColumnSorts` | Both | Unchanged | | `ColumnFilters` | `ColumnFilters` | Both | Unchanged (suppports multiple predicates) | | `GridFilter` | `GridFilter` | Both | Unchanged | | `RowGroupedColumns`(1) | `RowGroupedColumns` | Table | Unchanged | | `RowGroupedColumns`(2) | `PivotGroupedColumns` | Pivot | Unchanged (but with a new name) | | `ExpandedRowGroupValues` | `RowGroupValues` | Both | New (more complex) [`RowGroupValues`](https://www.adaptabletools.com/docs/reference/rowgroupvalues.md) object | | `AggregationColumns` (1) | `TableAggregationColumns` | Table | New [`TableAggregationColumns`](https://www.adaptabletools.com/docs/reference/tableaggregationcolumns.md) object | | `AggregationColumns` (2) | `PivotAggregationColumns` | Pivot | New [`PivotAggregationColumns`](https://www.adaptabletools.com/docs/reference/pivotaggregationcolumns.md) object | | `PinnedColumnsMap` | `ColumnPinning` | Both | New [`ColumnDirectionMap`](https://www.adaptabletools.com/docs/reference/columndirectionmap.md) object | | `ColumnHeadersMap` | `ColumnHeaders` | Both | Now [`ColumnStringMap`](https://www.adaptabletools.com/docs/reference/columnstringmap.md) object | | `SuppressAggFuncInHeader` | `SuppressAggFuncInHeader` | Both | Unchanged | | `RowSummaries` | `RowSummaries` | Both | Unchanged | | `Tags` | `Tags` | Both | Unchanged | | | `ColumnVisibility` | Table | New [`ColumnBooleanFalseMap`](https://www.adaptabletools.com/docs/reference/columnbooleanfalsemap.md) object | | | `AutoSizeColumns` | Both | New boolean property | | | `RowGroupDisplayType` | Table | Either 'single' or 'multi' | | | `ColumnGroupValues` | Both | New [`ColumnGroupValues`](https://www.adaptabletools.com/docs/reference/columngroupvalues.md) object | | | `PivotExpandLevel` | Pivot | New numeric property | | | `GrandTotalRow` | Both | New property | | | `PivotGrandTotal` | Pivot | New property | | | `PivotColumnTotal` | Pivot | New property | | | `MetaData` | Both | New ([Adaptable Object](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects)) property | | | `RowSelection` | Both | New property (added in [Version 22.1](https://www.adaptabletools.com/support/version-221-release-note)) | ## Extending Layouts By default, Layouts are simply sets of column visibility, order and related column properties. They do not include other [Adaptable Objects](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects), and everything in [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) is available in all Layouts. In other words, Layouts **do not include styling or formatting** information nor have a concept of Scope For some use cases this can be too restrictive - users might require some AdapTable Objects (e.g. styles, Alerts, Reports etc.) to be applicable to one Layout but not to another. This can be accomplished via **Object Tags** which leverage the `Tags` property found in each [Adaptable Object](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects#object-tags). See [Extending Layouts with Object Tags](https://www.adaptabletools.com/docs/handbook-layouts-extending/index.md) for more information and demos ## Using Layouts Run-time access to Layouts is primarily available in the Layout section of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md). - Layouts can also be accessed and managed from the Layout [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md), [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) and [Status Bar](https://www.adaptabletools.com/docs/ui-status-bar/index.md) - Many [Column](https://www.adaptabletools.com/docs/ui-column-menu/index.md) and [Context](https://www.adaptabletools.com/docs/ui-context-menu/index.md) Menu Items also provide quick access to Layout editing and related options This displays a list of existing Layouts with buttons to edit, clone, share or delete each Layout. There is also an `Add` button to enable run-time Users to create new Layouts via the [Layout Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md). ### Special Behaviour Because of their complexity and central importance, Layouts differ from many other AdapTable Objects in how they can be managed. Some of the unique features of managing Layouts at run-time include: - **Cloning**: Layouts can be cloned via a `Clone` button in each Layout; this opens the [Layout Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md) with the contents cloned from the Layout but the Name of the new Layout left blank - **Suspending**: Unlike with most Adaptable Objects, Layouts **cannot** be suspended - **Saving**: Like all Adaptable Objects, Layouts **save automatically** when relevant changes are made in AG Grid - **Sharing**: AdapTable will share Layouts using [Team Sharing](https://www.adaptabletools.com/docs/handbook-team-sharing/index.md) This will also share any AdapTable objects which the Layout references, e.g. [Calculated](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) or [FreeText](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) Columns - **Deleting** - Layouts can be deleted (if Permissions allows) but as there must always be one Layout, AdapTable will prevent the last Layout in [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) being deleted ### Layout Wizards AdapTable provides Layout Wizards to help run-time users create or edit Layouts in a series of steps. See [Table Layout Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md) or [Pivot Layout Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-pivot/index.md) for full instructions on configuring Layouts at runtime ## UI Entitlements The [UI Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) behaviour for Layouts is slightly more complicated than for other Modules, because Layouts are intrinsic to how AdapTable works. The rules are as follows: - `Full` Entitlement - everything works as expected and nothing is hidden or disabled. - `ReadOnly` Entitlement - existing Layouts can be selected, but Users cannot add, clone or delete them, nor edit them in Layout Wizard - Layouts are modifiable at run-time by users resizing / moving Columns in the UI or AG Grid Columns ToolPanel - However changes made to the Layout will not be persisted into State (nor available when the app next loads) It is possible to prevent any changes to the Layout but not by using Entitlements, but instead to: - Set up strict, initial Column Schema definitions in GridOptions that prevent undesired modifications - Or mark the Layout with `ReadOnly` set to _true_ and AdapTable will prevent any changes as much as possible - `Hidden` Entitlement - Layouts - and all Layout-related UI controls - are hidden from the User. - You still need to define at least one Layout (though the Layout UI controls will be invisible to the User) - AdapTable will update and persist the Layout as AG Grid changes, and re-load it on application re-start ### Read-Only Layouts Like all [Adaptable Objects](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects), Layouts can be set with `ReadOnly` as true. However, given the nature of Layouts this is more limited than with other objects. ## Advanced Layouts There are many advanced use cases regarding Layouts which AdapTable supports. These include: - [Programmatically Updating Layouts](https://www.adaptabletools.com/docs/handbook-layouts-updating/index.md) - [Synchronising Layouts](https://www.adaptabletools.com/docs/handbook-layouts-synchronising/index.md) - [Manually Saving Layouts](https://www.adaptabletools.com/docs/handbook-layouts-saving/index.md) ## Logging Layout Changes AdapTable provides additional and specific logging capability for Layouts. This logs to the console details of all changes to any Layout. See [Logging Layout Details](https://www.adaptabletools.com/docs/dev-guide-support-logging/index.md#layout-logging) for full details --- # Providing Default Layout Properties Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-default-props - AdapTable provides default Layout properties which will be used in all Layouts created at run-time - Additional props can be applied to all Layouts (new & existing) to enhance / extend functionality seamlessly - The State Options functions can be leveraged to define these props at design-time for greater flexibility AdapTable enables developers to configure default properties for both Table and Pivot Layouts. These are then applied automatically to Layouts created at runtime. Additionally, developers can extend all Layouts (new and existing) with custom properties to enhance functionality or patch existing configurations seamlessly. - This is different to the Default Layout that versions of AdapTable (prior to v.20) offered but which was removed - That was a full-blown Layout which AdapTable created if none was supplied ## Default Creation Properties Default creation properties are applied automatically to all new Table and Pivot Layouts **created at runtime**. These properties ensure consistency across newly created Layouts without requiring manual configuration. - Layouts created through [Layout API](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) will contain these properties (unless the property is explicitly overridden) - Layouts created via the UI wil show these properties in the [Layout Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md) (allowing the user to change them) This is done using the `layoutCreationDefaultProperties` property in [Layout Options](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md). ### `layoutCreationDefaultProperties` Sets default properties for new Layouts (Table or Pivot) [`DefaultLayoutProperties`](https://www.adaptabletools.com/docs/reference/layoutcreationdefaultproperties.md) Provides a set of Default Properties for new Layouts (Table or Pivot). The definition of the property is as follows: ``` layoutCreationDefaultProperties?: | LayoutCreationDefaultProperties | (( context: LayoutCreationDefaultPropertiesContext ) => TableLayoutCreationDefaultProperties | PivotLayoutCreationDefaultProperties); ``` As can be seen, the default properties can be provided as an object or via a function. Providing an Object It is possible to return a [`LayoutCreationDefaultProperties`](https://www.adaptabletools.com/docs/reference/layoutcreationdefaultproperties.md) which contains default properties for Table and Pivot Layouts: | Property | Type | Description | | --- | --- | --- | | [pivotLayout](https://www.adaptabletools.com/docs/reference/layoutcreationdefaultproperties.md#pivotlayout) | [`PivotLayoutCreationDefaultProperties`](https://www.adaptabletools.com/docs/reference/pivotlayoutcreationdefaultproperties.md) | Default properties to apply when creating a new Pivot Layout | | [tableLayout](https://www.adaptabletools.com/docs/reference/layoutcreationdefaultproperties.md#tablelayout) | [`TableLayoutCreationDefaultProperties`](https://www.adaptabletools.com/docs/reference/tablelayoutcreationdefaultproperties.md) | Default properties to apply when creating a new Table Layout | ```ts {4,12} // Provide default properties to be used im Table layoutOptions: { layoutCreationDefaultProperties: { tableLayout: { ColumnSorts: [ { ColumnId: 'name', SortOrder: 'Asc', }, ], }, pivotLayout: { PivotAggregationColumns: [ { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'github_watchers', AggFunc: 'sum', }, ], }, }, }, ``` Using a Function Alternatively you can provide a function which will return the object on a per-case basis. The function receives [`LayoutCreationDefaultPropertiesContext`](https://www.adaptabletools.com/docs/reference/layoutcreationdefaultpropertiescontext.md) which is defined as follows: | Property | Type | Description | | --- | --- | --- | | [layoutType](https://www.adaptabletools.com/docs/reference/layoutcreationdefaultpropertiescontext.md#layouttype) | `'table' \| 'pivot'` | Type of Layout ('table' \| 'pivot') | | [adaptableContext](https://www.adaptabletools.com/docs/reference/layoutcreationdefaultpropertiescontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | When using the function you return one of 2 objects: - [`DefaultTableLayoutProperties`](https://www.adaptabletools.com/docs/reference/tablelayoutcreationdefaultproperties.md) - set of Table Layout properties - [`DefaultPivotLayoutProperties`](https://www.adaptabletools.com/docs/reference/pivotlayoutcreationdefaultproperties.md) - set of Pivot Layout properties Neither of these objects allow you to provide a default `Name` property (since that has to be unique to the Layout) ``` layoutOptions: { layoutCreationDefaultProperties: (context: LayoutCreationDefaultPropertiesContext) => { if (context.layoutType == 'table') { return { ColumnSorts: [ { ColumnId: 'name', SortOrder: 'Asc', }, ], }; } else { return { PivotAggregationColumns: [ { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'github_watchers', AggFunc: 'sum', }, ], }; } }, }, ``` **Example: Default Creation Props** Providing Default Creation Props in Layout Options - In this example we have provided default creation properties for both Table and Pivot Layouts: - For Table Layouts - we default a on `Name` Column, and a [Column Filter](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) on `Language` Column - For Pivot Layouts - we default [Aggregations](https://www.adaptabletools.com/docs/handbook-aggregation/index.md) on `Github Stars` and `Github Watchers` Columns (suppressing the Agg Func), a [GrandTotalRow](https://www.adaptabletools.com/docs/handbook-aggregation-grand-total-row/index.md) at bottom and a [PivotGrandTotal](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md) Column before - In the Layout Toolbar click to add a new Table Layout and note that the new Layout already contains the Column Sort and Column Filter defined in default props - Then click to add a new Pivot Layout and note that the new Layout already contains the Aggregations, GrandTotalRow and PivotGrand Total Column ```ts import { AdaptableOptions, LayoutCreationDefaultPropertiesContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Default Layout Props', layoutOptions: { layoutCreationDefaultProperties: ( context: LayoutCreationDefaultPropertiesContext ) => { if (context.layoutType == 'table') { return { ColumnSorts: [ { ColumnId: 'name', SortOrder: 'Asc', }, ], ColumnFilters: [ { ColumnId: 'language', Predicates: [ { PredicateId: 'Is', Inputs: ['TypeScript'], }, ], }, ], AutoSizeColumns: true, }; } else { return { PivotAggregationColumns: [ { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'github_watchers', AggFunc: 'sum', }, ], SuppressAggFuncInHeader: true, GrandTotalRow: 'bottom', PivotGrandTotal: 'before', }; } }, }, initialState: { Dashboard: { ModuleButtons: ['Layout', 'SettingsPanel'], PinnedToolbars: ['Layout'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Table Layout', Layouts: [ { TableColumns: [ 'name', 'license', 'language', 'github_stars', 'open_pr_count', 'closed_issues_count', 'created_at', 'updated_at', 'pushed_at', 'created_at', 'has_wiki', 'github_watchers', 'description', 'open_issues_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Table Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ## Extending Initial State Layouts AdapTable allows developers to enhance **all** Layouts (new and existing) by manipulating the Layout State. This is most easily achieved by leveraging 2 [State Options](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-technical-reference/index.md) functions: - `applyState` - modifies the Layout state dynamically - `saveState` - controls how Layouts are persisted to avoid polluting the saved state with default configurations **Example: Default Layout Props** Providing Default Layout Properties via State Functions - This example demonstrates how to create default layout properties in Initial State; we: - Add a read-only `All Columns` Layout that includes all available columns with a default sort on `name` - Prevent the default `All Columns` Layout from being persisted by filtering it out in the `saveState` function in [State Options](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-technical-reference/index.md) - Apply a default descending sort on the `github_stars` column to all Layouts that do not contain a sort ```ts import {AdaptablePersistentState, Layout} from '@adaptabletools/adaptable'; import {AdaptableOptions, TableLayout} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Default Layout Props', initialState: { Layout: { CurrentLayout: 'Custom Layout', Layouts: [ { Name: 'Custom Layout', TableColumns: [ 'name', 'license', 'language', 'description', 'github_stars', ], }, ], }, Theme: {CurrentTheme: 'dark'}, Dashboard: { ModuleButtons: ['Layout', 'SettingsPanel'], PinnedToolbars: ['Layout'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, }, stateOptions: { applyState: (state, config) => { addAllColumnLayout(state); enhanceLayoutsWithDefaultSorting(state); return state; }, saveState: (state, config) => { // remove the default layout before saving state // we don't want to pollute the persisted state with it state.Layout.Layouts = state.Layout?.Layouts?.filter( layout => layout.Metadata?.DEFAULT_PROP !== true ) as [Layout, ...Layout[]]; }, }, }; function addAllColumnLayout(state: Partial) { const ALL_COLS_LAYOUT: TableLayout = { Metadata: { DEFAULT_PROP: true, }, IsReadOnly: true, Name: 'All Columns', TableColumns: [ 'name', 'license', 'language', 'github_stars', 'open_pr_count', 'closed_issues_count', 'created_at', 'updated_at', 'pushed_at', 'created_at', 'has_wiki', 'github_watchers', 'description', 'open_issues_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], ColumnSorts: [{ColumnId: 'name', SortOrder: 'Asc'}], }; state.Layout?.Layouts?.push(ALL_COLS_LAYOUT); } function enhanceLayoutsWithDefaultSorting( state: Partial ) { state.Layout?.Layouts?.forEach(layout => { if (layout.ColumnSorts?.length) { return; } layout.ColumnSorts = [{ColumnId: 'github_stars', SortOrder: 'Desc'}]; }); } ``` --- # Extending Layouts Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-extending - Layouts contain useful sets of column-related information - This means that they do not include Formats, Alerts and Reports etc - AdapTable provides a mechanism for users who find this restriction too constraining - Object Tags allow particular objects (e.g Formats) to be grouped with certain Layouts At their core, [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) are simply sets of **column-related properties**. They contain details of Column visibility, order, sorting, grouping, aggregations, filters and related properties. By default, Layouts **do not contain** other [Adaptable Objects](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects) like styling, formatting, Alerts or Flashing Cells This results in 2 types of "restrictions": - all [Adaptable Objects](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects) in [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) are automatically available in all Layouts, even though a user might prefer, for example, for some styles or Alerts to be applicable to one Layout but not another - developers cannot add custom objects, or properties, to their Layouts AdapTable therefore allows for Layouts to be extended to meet these 2 limitations: - object tags - so that some additional AdapTable objects are "included" in the Layout - metadata - to enable developers to provide additional bespoke information in the Layout ## AdapTable Objects AdapTable allows Layouts to be extended to have knowledge of specific Adaptable Objects. In other words developers can specify that a particular Report or Format Calculated Column is available in LayoutA but not LayoutB. ### Object Tags AdapTable Objects are extended into Layouts by using **Object Tags**. Object Tags are available to AdapTable Objects in these Modules: | Module | Extendable Object | | ---------------------------------------------------------------------------- | ------------------------------------- | | [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) | `AlertDefinition` | | [Custom Sort](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md) | `CustomSort` | | [Flashing Cell](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) | `FlashingCellDefinition` | | [Column Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) | `FormatColumn` | | [FreeText Column](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) | `FreeTextColumn` | | [Plus Minus](https://www.adaptabletools.com/docs/handbook-editing-plus-minus/index.md) | `PlusMinusNudge` | | [Shortcuts](https://www.adaptabletools.com/docs/handbook-editing-shortcut/index.md) | `Shortcut` | | [Styled Columns](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md) | `StyledColumn` | This approach leverages the `Tags` property, which exists in every [Adaptable Object](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects#object-tags), to list all the Layouts where the Object can be used - ideal for our purposes. ### Understanding Object Tags Every [Adaptable Object](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects#object-tags) has a `Tags` property of type [`AdaptableObjectTag`](https://www.adaptabletools.com/docs/reference/adaptableobjecttag.md) which can contain any value: ```ts export type AdaptableObjectTag = string; ``` Tags are designed to be an independent feature which be used for reasons other than extending Layouts Because this is such a popular use case, the `layoutTagOptions` section of [Layout Options](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) contains a number of properties designed to help developers easily achieve this - see below for more details **Example: Extended Layouts** Extending Layouts by using Tags to limit Scope - This demo illustrates how to leverage the `tags` property in [Adaptable Objects](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects#object-tags) to limit their scope to particular Layouts. - We provide 2 Layouts - `First Layout` and `Second Layout` with identical configuration - We also provide 5 Format Columns and 5 Styled Columns - all are given a Tag with the name of a Layout: - There are 5 [Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) provided: - `License` is **bold** - `First Layout` - `Language` is blue where value is 'TypeScript' - `First Layout` - `Github Stars` has a bespoke Style and a Display Format - `Second Layout` - Whole row is orange where `Language` value is 'HTML' - `Second Layout` - `Date` Columns are _Italicised_ and have a Display Format - `First Layout` **and** `Second Layout` - Additionally we provide 5 [Styled Columns](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md): - `Name` has a Badge Style - `First Layout` - `Open PRs` has a Gradient Column - `First Layout` - `Closed Issues` has a Percent Bar - `Second Layout` - `History` has a different Sparkline Column in `First Layout` and `Second Layout` - We set 2 properties to _true_ in the `layoutTagOptions` section of [Layout Options](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) to facilitate this: - `autoCheckTagsForLayouts` - tells a Layout to check all Objects to see if they include a Tag that matches its `Name` - `autoGenerateTagsForLayouts` - tells AdapTable to automatically add all Layouts to the Tags collection so they are visible in the UI ### Expand to see the how the Object Tags are applied The Layout Options are set up as follows: ```ts layoutOptions: { layoutTagOptions: { autoCheckTagsForLayouts: true, autoGenerateTagsForLayouts: true, }, }, ``` - Switch between the 2 Layouts to see the different [Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) and [Styled Columns](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md) applied - Edit one of the objects to change the Tags it contains and see how that affects the Layout ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Extended Layouts', layoutOptions: { layoutTagOptions: { autoCheckTagsForLayouts: true, autoGenerateTagsForLayouts: true, }, }, initialState: { Dashboard: { ModuleButtons: ['Layout', 'SettingsPanel'], PinnedToolbars: ['Layout'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'First Layout', Layouts: [ { TableColumns: [ 'name', 'history', 'license', 'language', 'github_stars', 'open_pr_count', 'closed_issues_count', 'created_at', 'updated_at', 'pushed_at', 'created_at', 'has_wiki', 'github_watchers', 'description', 'open_issues_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'First Layout', AutoSizeColumns: true, }, { TableColumns: [ 'name', 'language', 'github_stars', 'open_pr_count', 'history', 'closed_issues_count', 'created_at', 'updated_at', 'pushed_at', 'license', 'has_wiki', 'github_watchers', 'description', 'open_issues_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Second Layout', ColumnSizing: { history: {Width: 175}, }, AutoSizeColumns: true, }, ], }, StyledColumn: { StyledColumns: [ { ColumnId: 'name', Name: 'name Badge', BadgeStyle: { Badges: [ { PillStyle: { BackColor: 'DarkGray', }, }, ], }, Tags: ['First Layout'], }, { ColumnId: 'open_pr_count', Name: 'open_pr_count Gradient', GradientStyle: { CellRanges: [ { Min: 0, Max: 254, Color: '#a52a2a', }, ], }, Tags: ['First Layout'], }, { ColumnId: 'closed_issues_count', Name: 'closed_issues_count PercentBar', PercentBarStyle: { RangeValueType: 'Number', CellRanges: [ { Min: 0, Max: 21706, Color: 'purple', }, ], CellTextProperties: { CellTextLayout: { PercentValue: { Horizontal: 'Left', Vertical: 'Below' }, }, }, }, Tags: ['Second Layout'], }, { ColumnId: 'history', Name: 'history Sparkline', SparklineStyle: { options: { type: 'line', stroke: 'rgb(124, 255, 178)', strokeWidth: 2, padding: { top: 5, bottom: 5, }, marker: { enabled: true, size: 3, shape: 'diamond', }, }, }, Tags: ['First Layout'], }, { ColumnId: 'history', Name: 'history Sparkline', SparklineStyle: { options: { type: 'area', fill: 'rgba(216, 204, 235, 0.3)', stroke: 'rgb(119,77,185)', axis: { type: 'category', stroke: 'rgb(204, 204, 235)', }, }, }, Tags: ['Second Layout'], }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-license', Scope: { ColumnIds: ['license'], }, Style: { FontWeight: 'Bold', }, Tags: ['First Layout'], }, { Name: 'formatColumn-github_stars', Scope: { ColumnIds: ['github_stars'], }, Style: { ForeColor: '#c2bb00', BackColor: '#f5f5f5', }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { Prefix: 'Stars: ', }, }, Tags: ['Second Layout'], }, { Name: 'formatColumn-date', Scope: { DataTypes: ['date'], }, Style: { FontStyle: 'Italic', Alignment: 'Center', }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'MMM do yyyy', }, }, Tags: ['First Layout', 'Second Layout'], }, { Name: 'formatColumn-language', Style: { BackColor: '#87cefa', }, Scope: { ColumnIds: ['language'], }, Rule: { Predicates: [ { PredicateId: 'Is', Inputs: ['TypeScript'], }, ], }, Tags: ['First Layout'], }, { Name: 'formatColumn-all', Style: { BackColor: 'orange', }, Scope: { All: true, }, Rule: { BooleanExpression: '[language] = "HTML"', }, Tags: ['Second Layout'], }, ], }, }, }; ``` ```ts import {ColDef} from 'ag-grid-enterprise'; export const columnDefs: ColDef[] = [ { field: 'name', cellDataType: 'text', sortable: true, }, { field: 'language', cellDataType: 'text', enablePivot: true, enableRowGroup: true, }, { field: 'github_stars', headerName: 'GitHub Stars', cellDataType: 'number', type: 'github', enableValue: true, }, { field: 'github_watchers', headerName: 'GitHub Watchers', cellDataType: 'number', type: 'github', enableValue: true, }, { 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', type: 'issue-pr', enableValue: true, }, { field: 'closed_issues_count', headerName: 'Closed Issues', cellDataType: 'number', type: 'issue-pr', enableValue: true, }, { field: 'open_pr_count', headerName: 'Open PRs', cellDataType: 'number', type: 'issue-pr', enableValue: true, }, { field: 'closed_pr_count', headerName: 'Closed PRs', cellDataType: 'number', type: 'issue-pr', 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, }, { headerName: 'History', colId: 'history', field: 'history', editable: false, floatingFilter: false, filter: false, resizable: true, cellDataType: 'numberArray', }, ]; ``` ```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: 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('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, 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('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, 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('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, 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('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, 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('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, 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('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, 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('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, 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('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, 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('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, 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('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, 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('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, 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('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, 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('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, 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('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, 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('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, 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('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, 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('2021-12-17T11:03:37').toDateString(), 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('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, 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('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, 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('2021-11-28T16:21:43').toDateString(), 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('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, 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('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, 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('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, 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('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, history: [26, 12, 7, 13, 17, 18, 20, 1, 28, 23, 22, 2, 2, 22, 18, 29, 2], }, ]; ``` ### Configuring Object Tags Developers are able to set up Object Tags in AdapTable in order to extend Layouts. ### Setting up Object Tags to Extend Layouts There are the steps required to extend Layouts by leveraging Object Tags: Set `autoGenerateTagsForLayouts` in `layoutTagOptions` section of [Layout Options](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md)) to _true_. AdapTable will create an Object Tag entry for every Layout. ```tsx {4} const adaptableOptions: AdaptableOptions = { layoutOptions: { layoutTagOptions: { autoGenerateTagsForLayouts: true, autoCheckTagsForLayouts: true, }, }, }; ``` Set `autoCheckTagsForLayouts` in `layoutTagOptions` section of [Layout Options](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md)) to _true_. AdapTable will now check if an Object's Tags are available in the current Layout (i.e. include Layout name) ```tsx {5} const adaptableOptions: AdaptableOptions = { layoutOptions: { layoutTagOptions: { autoGenerateTagsForLayouts: true, autoCheckTagsForLayouts: true, }, }, }; ``` Define any required Layout(s) in [Layout Initial State](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md). Create the Layouts as usual - nothing special is required. ```tsx {6,10} Layout: { CurrentLayout: 'First Layout', Layouts: [ { TableColumns: ['name', 'language', 'description'], Name: 'First Layout', }, { TableColumns: ['license', 'has_wiki', 'has_pages'], Name: 'Second Layout', }, ], }, ``` Create other Initial Adaptable State as needed. Add a `Tags` property to each Object that you wish to scope to a given Layout (or Layouts) only. Provide the name of the Layout(s) as an array to the property. ```tsx {6,11} FormatColumn: { FormatColumns: [ { Name: 'FormatColumn-name-270', Scope: { ColumnIds: ['name'] }, Style: { FontWeight: 'Bold' }, Tags: ['First Layout'], }, { Name: 'FormatColumn-text-271', Scope: { ColumnIds: ['text'] }, Style: { FontStyle: 'Italic', }, Tags: ['First Layout', 'Second Layout'], }, ], } ``` ### Using Object Tags End Users are also able to manage Layouts using Object Tags. If Tags have been provided, each Object's Creation Wizard will include an additional step called 'Tags'. This lists all the Tags which have been provided, together with a Checkbox. Ticking the Checkbox will limit the scope of the Object just to the checked Layouts. ### Layout Tag Options Three properties in the `layoutTagOptions` section of Layout Options aid in the creation of Object Tags: ### `autoCheckTagsForLayouts` AdapTable Automatically checks if an Adaptable Object's Tags are available in the current Layout Set this property to _true_ to tell AdapTable to check whether the [Object Tags](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects#object-tags) of each Adaptable Object includes the name of the current Layout. If set to _true_, an Adaptable Object only displays in Layouts whose `Name` is included in the it's `Tags` property If an Adaptable Object has **no** Tags (and this property is _true_) then it is available in **every** Layout ```ts {4} // Only display Adaptable Objects which contain the name of the current Layout in the Tags property const adaptableOptions: AdaptableOptions = { layoutOptions: { autoCheckTagsForLayouts: false, }, }; ``` - For a more granular application use the `isObjectExtendedInLayout` property instead - This provides a custom function that allows a per Object and Layout approach ### `autoGenerateTagsForLayouts` Whether AdapTable should create an Object Tag for every Layout A popular application of [Object Tags](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects#object-tags) is to use them to list the Layouts where they can be applied (and only there). To facilitate this, AdapTable can be configured to automatically create a Tag for each Layout in AdapTable State. These are added to the list of Tags that users provide in the `objectTags` property of [User Interface Options](https://www.adaptabletools.com/docs/ui-technical-reference/index.md) The property is defined s follows: ```ts autoGenerateTagsForLayouts?: | boolean | ((context: AutoGenerateTagsForLayoutsContext) => AdaptableObjectTag[]); ``` As can be seen it has 2 different return types: - Boolean This simply returns _true_ or _false_ if AdapTable should generate a Tag for every Layout ```ts {4} // Generate a Tag for every Layout in Adaptable State const adaptableOptions: AdaptableOptions = { layoutOptions: { autoGenerateTagsForLayouts: false, }, }; ``` - Function For more advanced scenarios a bespoke function can be provided. AdapTable will invoke this function each time a list of Tags is required. Provide this property if you want to create Object Tags for just some of the available Layouts The function receives an `AutoGenerateTagsForLayoutsContext` property and returns an array of [`AdaptableObjectTag`](https://www.adaptabletools.com/docs/reference/adaptableobjecttag.md). The [`AutoGenerateTagsForLayoutsContext`](https://www.adaptabletools.com/docs/reference/autogeneratetagsforlayoutscontext.md) object contains 2 collections: | Property | Type | Description | | --- | --- | --- | | [layouts](https://www.adaptabletools.com/docs/reference/autogeneratetagsforlayoutscontext.md#layouts) | [`Layout`](https://www.adaptabletools.com/docs/reference/layout.md)`[]` | Layouts currently in Adaptable State | | [objectTags](https://www.adaptabletools.com/docs/reference/autogeneratetagsforlayoutscontext.md#objecttags) | [`AdaptableObjectTag`](https://www.adaptabletools.com/docs/reference/adaptableobjecttag.md)`[]` | Object Tags provided in User Interface Options | | [adaptableContext](https://www.adaptabletools.com/docs/reference/autogeneratetagsforlayoutscontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```ts {4,5,6} // Generate a Tag only for Layouts which include the word 'Custom' in the Name const adaptableOptions: AdaptableOptions = { layoutOptions: { autoGenerateTagsForLayouts: ( context: AutoGenerateTagsForLayoutsContext ) => { return context.layouts .filter(l => l.Name.includes('Custom')) .map(l => l.Name); }, }, }; ``` ### `isObjectExtendedInLayout` Checks if the provided Adaptable Object is available in the given Layout This property checks for each [Adaptable Object](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects) whether it should be made available in the currently applied Layout. It is provided for 2 different scenarios: - When [Object Tags](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects#object-tags) are being used to limit object scope but the `autoCheckTagsForLayouts` property is too broadly applied and a more granular approach is required - If Tags are not being used and a totally bespoke approach is preferred to limit Object / Layout scope You can still provide this property if **not** using Object Tags This is a **boolean function** which receives a `context` property of type [`LayoutExtendedContext`](https://www.adaptabletools.com/docs/reference/layoutextendedcontext.md) defined as follows: | Property | Type | Description | | --- | --- | --- | | [adaptableObject](https://www.adaptabletools.com/docs/reference/layoutextendedcontext.md#adaptableobject) | [`LayoutExtensionObject`](https://www.adaptabletools.com/docs/reference/layoutextensionobject.md) | Object being checked | | [layout](https://www.adaptabletools.com/docs/reference/layoutextendedcontext.md#layout) | [`Layout`](https://www.adaptabletools.com/docs/reference/layout.md) | Current Layout | | [module](https://www.adaptabletools.com/docs/reference/layoutextendedcontext.md#module) | [`LayoutExtensionModule`](https://www.adaptabletools.com/docs/reference/layoutextensionmodule.md) | Current Adaptable Module | | [adaptableContext](https://www.adaptabletools.com/docs/reference/layoutextendedcontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | ```ts {4,5,6,7,8} // Allow all ReadOnly Adaptable Objects to be available // Limit the scope of other AdapTable Objects to Layouts which include the word 'Custom' in the Name const adaptableOptions: AdaptableOptions = { layoutOptions: { isObjectExtendedInLayout: (context: LayoutExtendedContext) => { if (context.adaptableObject.IsReadOnly) { return true; } return context.layout.Name.includes('Custom'); }, }, }; ``` ### Creating Extended Layouts The `createOrUpdateExtendedLayout` function in [Layout API](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) enables creating or updating Extended Layouts. ### `createOrUpdateExtendedLayout` Receives an Extended Layout and saves it, and all extended Objects, to State This function receives an Extended Layout and saves it to State. The main, Layout, is saved with Layouts and any Extensions are saved to the associated parts of AdapTable State. If the object already exists in State, then it is updated with what is passed into the Object ```ts {10,11} // Create an Extended Layout with a Styled Column const extendedLayout: ExtendedLayout = { Layout: importedLayout, // the Layout object to import Extensions: [ { Module: 'StyledColumn', Object: badgeStyle, // a previously defined Badge Style }, ], }; // Import the Extended Layout and then Select it to be current adaptableApi.layoutApi.createOrUpdateExtendedLayout(extendedLayout); adaptableApi.layoutApi.setExtendedLayout(extendedLayout); ``` ### Retrieving Extended Layouts AdapTable also provides the `getExtendedLayoutByName` helper function in [Layout API](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) which can fetch an Extended Layout from AdapTable State. This is particularly useful if wanting to share or clone an Extended Layout (see below) ### `getExtendedLayoutByName` Returns the full Extended Layout object with the given name This function returns an Extended Layout with the provided name. The return object is of type of [`ExtendedLayout`](https://www.adaptabletools.com/docs/reference/extendedlayout.md) defined as follows: | Property | Type | Description | | --- | --- | --- | | [Extensions](https://www.adaptabletools.com/docs/reference/extendedlayout.md#extensions) | [`LayoutExtension`](https://www.adaptabletools.com/docs/reference/layoutextension.md)`[]` | Object to be included in the Layout | | [Layout](https://www.adaptabletools.com/docs/reference/extendedlayout.md#layout) | [`Layout`](https://www.adaptabletools.com/docs/reference/layout.md) | Layout being extended | ```ts {3} // Get the full Extended Layout for the Current Layout and output to console const layoutApi: LayoutApi = adaptableApi.layoutApi; const extendedLayout: ExtendedLayout = layoutApi.getExtendedLayoutByName( layoutApi.getCurrentLayoutName() ); ``` ### Sharing Extended Layouts By their nature, Extended Layouts are not stored as a single, composite object in [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md). Instead, the main properties are in the Layout object, but extended objects (e.g. Format Columns or Custom Sorts) are stored in the appropriate State section. This means that it is not possible, easily, to share an Extended Layout as a single object. However by using the 2 functions above - `getExtendedLayoutByName` and `createOrUpdateExtendedLayout` - it is possible to fetch an ExtendedLayout and make any changes to it as needed. A better way to do this is via [Referenced Team Sharing](https://www.adaptabletools.com/docs/handbook-team-sharing-referenced/index.md) which allows a Layout to be shared between team members **Example: Sharing Extended Layouts** Sharing an Extended Layout - This example has an initial Layout ('First Layout') extended with 4 Format Columns - A Custom Dashboard Button imports - and sets - a new Extended Layout ('Extended Layout') with 2 Styled Columns - When a Layout is Selected we send a System Status message with its contents (and log the full object to the console()) - Click the button to import and set the new Extended Layout and note that you see the Layout and the 2 Styled Columns - Open the System Status popup to see the contents of the Extended Layout - Open the Console and switch between Layouts to see the full Extended Layout object ```ts import { AdaptableButton, AdaptableOptions, CustomToolbarButtonContext, ExtendedLayout, StyledColumn, TableLayout, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Sharing Extended Layouts', dashboardOptions: { customToolbars: [ { name: 'ButtonToolbar', title: 'Buttons', toolbarButtons: [ { label: 'Import (and Select) Extended Layout', onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { // Define an Extended Layout with 2 Styled Columns and Import and select it const badgeStyle: StyledColumn = { ColumnId: 'name', Name: 'name Badge', Tags: ['Imported Layout'], BadgeStyle: { Badges: [ { PillStyle: { BackColor: 'DarkGray', }, }, ], }, }; const gradientStyle: StyledColumn = { ColumnId: 'open_pr_count', Name: 'open_pr_count Gradient', Tags: ['Imported Layout'], GradientStyle: { CellRanges: [ { Min: 0, Max: 254, Color: '#a52a2a', }, ], }, }; const importedLayout: TableLayout = { Name: 'Imported Layout', TableColumns: [ 'name', 'license', 'language', 'github_stars', 'open_pr_count', ], }; const extendedLayout: ExtendedLayout = { Layout: importedLayout, Extensions: [ { Module: 'StyledColumn', Object: badgeStyle, }, { Module: 'StyledColumn', Object: gradientStyle, }, ], }; context.adaptableApi.layoutApi.createOrUpdateExtendedLayout( extendedLayout ); context.adaptableApi.layoutApi.setLayout(importedLayout.Name); // JW TODO context.adaptableApi.layoutApi.setExtendedLayout(extendedLayout); }, buttonStyle: { tone: 'info', variant: 'text', }, }, ], }, ], }, layoutOptions: { layoutTagOptions: { autoCheckTagsForLayouts: true, autoGenerateTagsForLayouts: true, }, }, initialState: { Dashboard: { ModuleButtons: [ 'Layout', 'FormatColumn', 'StyledColumn', 'SystemStatus', 'SettingsPanel', ], Tabs: [ { Name: 'Demo', Toolbars: ['ButtonToolbar', 'Layout', 'SystemStatus'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'First Layout', Layouts: [ { TableColumns: [ 'name', 'license', 'language', 'github_stars', 'open_pr_count', 'closed_issues_count', 'created_at', 'updated_at', 'pushed_at', 'created_at', 'has_wiki', 'github_watchers', 'description', 'open_issues_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'First Layout', AutoSizeColumns: true, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-license', Scope: { ColumnIds: ['license'], }, Style: { FontWeight: 'Bold', }, Tags: ['First Layout'], }, { Name: 'formatColumn-date', Scope: { DataTypes: ['date'], }, Style: { FontStyle: 'Italic', Alignment: 'Center', }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'MMM do yyyy', }, }, Tags: ['First Layout'], }, { Name: 'formatColumn-language', Style: { BackColor: '#87cefa', }, Scope: { ColumnIds: ['language'], }, Rule: { Predicates: [ { PredicateId: 'Is', Inputs: ['TypeScript'], }, ], }, Tags: ['First Layout'], }, { Name: 'formatColumn-all', Style: { BackColor: 'orange', }, Scope: { All: true, }, Rule: { BooleanExpression: '[language] = "HTML"', }, Tags: ['First Layout'], }, ], }, }, }; ``` ```ts import { AdaptableReadyInfo, ExtendedLayout, LayoutApi, LayoutChangedAction, } from '@adaptabletools/adaptable'; export const onAdaptableReady = async ({adaptableApi}: AdaptableReadyInfo) => { adaptableApi.eventApi.on('LayoutChanged', layoutChangedInfo => { const actionName: LayoutChangedAction = layoutChangedInfo.actionName; if (actionName == 'LAYOUT_SELECT' || actionName == 'LAYOUT_READY') { const layoutApi: LayoutApi = adaptableApi.layoutApi; const currentLayoutName: string = layoutApi.getCurrentLayoutName(); const extendedLayout: ExtendedLayout | undefined = layoutApi.getExtendedLayoutByName(currentLayoutName); if (extendedLayout) { adaptableApi.systemStatusApi.setInfoSystemStatus( currentLayoutName, JSON.stringify(extendedLayout) ); console.log(currentLayoutName, extendedLayout); } } }); }; ``` ### Cloning Extended Layouts Extended Layouts, like regular Layouts, can be be cloned. AdapTable will clone the underlying Layout and all the objects that are being extended (e.g. Format Columns or Styled Columns). This is done using the `cloneExtendedLayout` function in [Layout API](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md). ### `cloneExtendedLayout` Clones an Extended Layout This function returns an Extended Layout, with the given name, which clones the one provided. The return object is of type of [`ExtendedLayout`](https://www.adaptabletools.com/docs/reference/extendedlayout.md) defined as follows: | Property | Type | Description | | --- | --- | --- | | [Extensions](https://www.adaptabletools.com/docs/reference/extendedlayout.md#extensions) | [`LayoutExtension`](https://www.adaptabletools.com/docs/reference/layoutextension.md)`[]` | Object to be included in the Layout | | [Layout](https://www.adaptabletools.com/docs/reference/extendedlayout.md#layout) | [`Layout`](https://www.adaptabletools.com/docs/reference/layout.md) | Layout being extended | ```ts {4} // Retrieve the "Hello" Layout and clone it with the new name "Goodbye" const layoutApi: LayoutApi = adaptableApi.layoutApi; const layoutToExtend: ExtendedLayout = layoutApi.getExtendedLayoutByName('Hello'); const extendedLayout: ExtendedLayout = layoutApi.cloneExtendedLayout( layoutToExtend, 'Goodbye' ); ``` - Both original and cloned Layouts will now reference the same extended objects - This means that changing that object (e.g. a Format Column) will be reflected in both Layouts **Example: Cloning Extended Layouts** Cloning an Extended Layout - This example has an Extended Layout ('Original Layout') which we clone 1. Click first the button to clone (and then set) the Extended Layout and note that all extended objects have been cloned 2. Click the second button (which becomes enabled) to change the style for the `Language` Column 3. Switch Layouts and note that you see the new style in the original Layout also ```ts import { AdaptableButton, AdaptableOptions, AdaptableStyle, CustomToolbarButtonContext, ExtendedLayout, FormatColumn, FormatColumnApi, LayoutApi, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Cloning Extended Layouts', dashboardOptions: { customToolbars: [ { name: 'ButtonToolbar', title: 'Buttons', toolbarButtons: [ { label: 'Clone Extended Layout', onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { const layoutApi: LayoutApi = context.adaptableApi.layoutApi; const layoutToExtend: ExtendedLayout | undefined = layoutApi.getExtendedLayoutByName('Original Layout'); if (layoutToExtend) { const clonedLayout: ExtendedLayout | false = layoutApi.cloneExtendedLayout( layoutToExtend, 'Cloned Layout' ); if (clonedLayout !== false) { context.adaptableApi.layoutApi.setLayout( clonedLayout.Layout.Name ); } } }, buttonStyle: { tone: 'info', variant: 'text', }, }, { label: 'Change Language Style', onClick: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { const formatColumnApi: FormatColumnApi = context.adaptableApi.formatColumnApi; const formatColumn: FormatColumn = formatColumnApi.getFormatColumnsForColumnId('language')[0]; if (formatColumn) { const style: AdaptableStyle | undefined = { BackColor: 'Green', }; formatColumn.Style = style; formatColumnApi.editFormatColumn(formatColumn); } }, buttonStyle: { tone: 'success', variant: 'text', }, disabled: ( button: AdaptableButton, context: CustomToolbarButtonContext ) => { return context.adaptableApi.layoutApi.getLayouts().length == 1; }, }, ], }, ], }, layoutOptions: { layoutTagOptions: { autoCheckTagsForLayouts: true, autoGenerateTagsForLayouts: true, }, }, initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['ButtonToolbar', 'Layout'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Original Layout', Layouts: [ { TableColumns: [ 'name', 'license', 'language', 'github_stars', 'open_pr_count', 'closed_issues_count', 'created_at', 'updated_at', 'pushed_at', 'created_at', 'has_wiki', 'github_watchers', 'description', 'open_issues_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Original Layout', AutoSizeColumns: true, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-license', Scope: { ColumnIds: ['license'], }, Style: { FontWeight: 'Bold', }, Tags: ['Original Layout'], }, { Name: 'formatColumn-date', Scope: { DataTypes: ['date'], }, Style: { FontStyle: 'Italic', Alignment: 'Center', }, DisplayFormat: { Formatter: 'DateFormatter', Options: { Pattern: 'MMM do yyyy', }, }, Tags: ['Original Layout'], }, { Name: 'formatColumn-language', Style: { BackColor: '#87cefa', }, Scope: { ColumnIds: ['language'], }, Rule: { Predicates: [ { PredicateId: 'Is', Inputs: ['TypeScript'], }, ], }, Tags: ['Original Layout'], }, { Name: 'formatColumn-all', Style: { BackColor: 'orange', }, Scope: { All: true, }, Rule: { BooleanExpression: '[language] = "HTML"', }, Tags: ['Original Layout'], }, ], }, }, }; ``` ## Meta Data Sometimes developers want to extend Layouts by including their own custom bespoke properties and objects. A common use case is to include the Author or the Team or other organisation-specific details This is done by using the `Metadata` property (of type `any`) which is in the [Adaptable Object](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects) type, from which the Layout object derives. Unlike most properties in the Layout, `MetaData` can only be added at design-time or programmatically **Example: Layouts With Metadata** Adding MetaData to Layouts - This example shows how to use Layout Meta data. We add a `Metadata` property to 4 layouts: - `First Layout` and `Third Layout` - have `Metadata` property of 'Large' - and they show the Dashboard, open the Tool Panel and use dark theme - `Second Layout` and `Fourth Layout` - have `Metadata` property of 'Small' - and they hide the Dashboard, close the Tool Panel and use light dark theme - Switch between the Layouts (you might need to use the status bar when the Dashboard is hidden!) to see how we listen to MetaData and change the grid accordingly ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Layout Meta Data', initialState: { Dashboard: { ModuleButtons: ['Layout', 'SettingsPanel'], PinnedToolbars: ['Layout'], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'First Layout', Layouts: [ { TableColumns: [ 'name', 'license', 'language', 'github_stars', 'open_pr_count', 'closed_issues_count', 'created_at', 'updated_at', 'pushed_at', 'has_wiki', 'github_watchers', 'description', 'open_issues_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'First Layout', AutoSizeColumns: true, Metadata: 'Large', }, { TableColumns: [ 'name', 'language', 'github_stars', 'open_pr_count', 'closed_issues_count', 'created_at', 'updated_at', 'pushed_at', 'license', 'has_wiki', 'github_watchers', 'description', 'open_issues_count', 'closed_pr_count', 'has_projects', 'has_pages', 'week_issue_change', ], Name: 'Second Layout', RowGroupedColumns: ['language'], AutoSizeColumns: true, Metadata: 'Small', }, { Name: 'Third Layout', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'count', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], Metadata: 'Large', }, { Name: 'Fourth Layout', PivotColumns: [], PivotGroupedColumns: ['license'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'Total', AggFunc: 'sum', }, ], Metadata: 'Small', }, ], }, }, }; ``` ```ts import { AdaptableApi, AdaptableReadyInfo, LayoutChangedInfo, } from '@adaptabletools/adaptable'; export const onAdaptableReady = (info: AdaptableReadyInfo) => { const adaptableApi = info.adaptableApi; function updateGrid(adaptableApi: AdaptableApi): void { const currentLayout = adaptableApi.layoutApi.getCurrentLayout(); console.log('Metadata', currentLayout.Metadata); console.log('Metadata2', currentLayout.Metadata?.toString()); if (currentLayout.Metadata?.toLocaleString().includes('Small')) { adaptableApi.dashboardApi.hideDashboard(); adaptableApi.toolPanelApi.closeAdapTableToolPanel(); adaptableApi.themeApi.loadLightTheme(); adaptableApi.filterApi.columnFilterApi.hideQuickFilterBar(); } else if (currentLayout.Metadata?.toLocaleString().includes('Large')) { adaptableApi.dashboardApi.showDashboard(); adaptableApi.toolPanelApi.openAdapTableToolPanel(); adaptableApi.themeApi.loadDarkTheme(); adaptableApi.filterApi.columnFilterApi.showQuickFilterBar(); } } updateGrid(adaptableApi); adaptableApi.eventApi.on( 'LayoutChanged', (layoutChangedInfo: LayoutChangedInfo) => { console.log('info', layoutChangedInfo); if (layoutChangedInfo.actionName === 'LAYOUT_SELECT') { updateGrid(adaptableApi); } } ); }; ``` --- # Monitoring Layout Changes Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-monitoring - The Layout Changed Event fires whenever a Layout is changed AdapTable provides a **Layout Changed Event** which fires whenever the Layout State changes. It provides full information about the changes to the Layout and what triggered the change ### Understanding the Layout Changed Event **LayoutChangedInfo** The event comprises a single [`LayoutChangeInfo`](https://www.adaptabletools.com/docs/reference/layoutchangedinfo.md) object which contains the old and new Layout State. It also includes details about what action triggered the change: | Property | Type | Description | | --- | --- | --- | | [actionName](https://www.adaptabletools.com/docs/reference/layoutchangedinfo.md#actionname) | [`LayoutChangedAction`](https://www.adaptabletools.com/docs/reference/layoutchangedaction.md) | What caused Layout State to change | | [newLayoutState](https://www.adaptabletools.com/docs/reference/layoutchangedinfo.md#newlayoutstate) | [`LayoutState`](https://www.adaptabletools.com/docs/reference/layoutstate.md) | Current Layout State | | [oldLayoutState](https://www.adaptabletools.com/docs/reference/layoutchangedinfo.md#oldlayoutstate) | [`LayoutState`](https://www.adaptabletools.com/docs/reference/layoutstate.md)` \| undefined` | Previous Layout State | | [adaptableContext](https://www.adaptabletools.com/docs/reference/layoutchangedinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` | **Layout Changed Actions** The value for the `actionName` property is of type [`LayoutChangedAction`](https://www.adaptabletools.com/docs/reference/layoutchangedaction.md) This contains all the possible actions that can cause the Layout State to change: **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('LayoutChanged', (eventInfo: LayoutChangedInfo) => { // do something with the info }); ``` **Example: Layout Changed** Event triggered when the Layout is changed - This demo listens to the Layout Changed Event and outputs a [System Status Message](https://www.adaptabletools.com/docs/handbook-system-status-message/index.md) describing what happened in the Layout ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Layout Changed Event', initialState: { Dashboard: { Tabs: [ { Name: 'Demo', Toolbars: ['SystemStatus'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Standard Layout', Layouts: [ { TableColumns: [ 'action', 'name', 'language', 'github_stars', 'license', 'created_at', 'has_wiki', 'updated_at', 'topics', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo, LayoutChangedInfo} from '@adaptabletools/adaptable'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { adaptableApi.toolPanelApi.openAdapTableToolPanel(); adaptableApi.eventApi.on('LayoutChanged', (info: LayoutChangedInfo) => { adaptableApi.systemStatusApi.setInfoSystemStatus( 'Layout Change Event: ' + info.actionName ); }); }; ``` --- # Pivot Layouts Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-pivot - Pivot Layouts enable AG Grid instances with Pivoting to be defined - All elements of pivoting are supported - Pivot Columns, Row Groups and Aggregations - Pivot Layouts can also include Format Column styles - Pivot Layouts can be defined at design-time through Initial Adaptable State, or created at runtime in the UI Wizard AdapTable provides full Pivoting support through Pivot Layouts. These are Layouts which define pivoting requirements and will open AG Grid in pivot mode. Do **not** set `pivotMode` to *true* in GridOptions; instead define a Pivot Layout and AdapTable will take care of the rest They will automatically display any provided pivot, row-grouping and aggregation columns. Pivot Layouts can be provided in 2 ways: - by developers at design-time using Layout Initial State - by run-time users using the AdapTable Layout UI Wizard ## Understanding Pivot Layouts Pivot Layouts display aggregated or summarised data. Users can "slice and dice" their data, ie. configure rows and columns differently to perform aggregations. When using Pivot Layouts, large amounts of data can be reduced to a compact consumable view, so grid users can view only those dimensions (and data) relevant at any particular point of time. - Pivot Grids are called this because, essentially the data is "pivoted" or rotated - In other words data, which in Table Layouts would be viewed as part of a row, is pivoted to form a Column ### Pivoting in AG Grid [AG Grid's Pivoting capabilities](https://www.ag-grid.com/javascript-data-grid/pivoting/) are best of class, offering a full and powerful set of pivot-related features. To understand how pivoting works in AG Grid it is worth distinguishing between 2 types of Columns: - Columns which exist in the `ColDefs` and which **configure** the pivoting (and definable in a Pivot Layout) - Columns **dynamically generated** by AG Grid when pivoting (i.e. absent from `ColDefs` and Pivot Layouts) There are 3 sets of 'configurable' columns provided by AG Grid that each creates generated columns. Each of these Columns are fully supported by AdapTable and available in Pivot Layouts - `PivotAggregationColumns` contain the values which are aggregated and displayed in [Pivot Result Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-result-columns/index.md) - `PivotColumns` generate [Pivot Column Groups](https://www.ag-grid.com/javascript-data-grid/pivoting-column-groups/) for each unique value they contain - `PivotGroupedColumns` generate [Pivot Row Grouped Columns](https://www.ag-grid.com/javascript-data-grid/grouping-data/) with a row for each distinct column value - A Pivot Result Column is generated for each **unique permutation** of Pivot Column value & Aggregation Column - If there are no Pivot Columns, then no Pivot Column Groups are created (but Pivot Result Columns still display) This table shows how AG Grid configures the 3 Pivot-related Column types in `ColDefs`, the columns they generate, the Columns Tool Panel section they appear in and the property required to make them "draggable". | AdapTable Pivot Layout | Generated Columns | Tool Panel Section | "Draggable" prop | ColDef Prop | | ------------------------- | ------------------------- | ------------------ | ---------------- | ----------- | | `PivotAggregationColumns` | Pivot Result Columns | Values | `enableValue` | `aggFunc` | | `PivotColumns` | Pivot Column Groups | Column Labels | `enablePivot` | `pivot` | | `PivotGroupedColumns` | Pivot Row Grouped Columns | Row Groups | `enableRowGroup` | `rowGroup` | **Example: Pivot Layouts** Creating Pivot Layouts In AdapTable - This Demo creates 2 Pivoting Layouts (as well as a Table Layout) using the 3 types of Columns described above: - `Pivot Cols Layout` - which is set as the *CurrentLayout* - and has the following features: - **1 PivotGroupedColumn**: `Language` - generates the **Pivot Row Grouped Column** named `Group` - **1 PivotColumn**: `License` - AG Grid generates 3 **Pivot Column Groups** (`BSD 3-Clause`, `MIT Licence` & `Other`) to map the column's 3 unique values - **2 PivotAggregationColumns**: `Github Stars` & `Github Watchers` with `sum` & `count` aggFuncs; AG Grid generates 6 **Pivot Result Columns** (1 for each column in the 3 Pivot Column Groups) - `Pivot Sum Layout` - which has the following features: - **1 PivotGroupedColumn**: `License` - **3 PivotAggregationColumns**: `Github Stars`, `Github Watchers` and `Total` - all using `sum` aggregation (note: `Total` is an aggregatable [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md)) - **No PivotColumns**: Pivot Layouts do not need to include pivot columns ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivoted Layouts', 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, }, }, ], }, Layout: { CurrentLayout: 'Pivot Cols Layout', Layouts: [ { Name: 'Pivot Cols Layout', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'count', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSizing: { week_issue_change: {Width: 475}, }, }, { Name: 'Pivot Sum Layout', PivotColumns: [], PivotGroupedColumns: ['license'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'Total', AggFunc: 'sum', }, ], }, { Name: 'Standard Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', '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'); }; ``` ## Defining Pivot Layouts Pivot Layouts can be provided in 2 main ways: - configured by [developers at design-time](https://www.adaptabletools.com/docs/handbook-layouts-pivot-defining/index.md) using [Pivot Layout Initial Adaptable State](https://www.adaptabletools.com/docs/handbook-layouts-pivot-technical-reference/index.md) - created or edited by run-time users using the [Pivot Layout UI Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-pivot/index.md) ## Opening Pivot Cells as Tables AdapTable allows any cell in a Pivot Layout to be viewed in a Table. This is done via a [Context Menu Item](https://www.adaptabletools.com/docs/ui-context-menu/index.md) entitled `Expand Aggregated Value`. The menu item appears in all Pivot Layout Cells, dynamically created Pivot Result Columns and Aggregation Columns Selecting this Menu Item will open a Table that shows all the cells that make up the pivot cell (e.g. which row groups, pivot columns etc have been selected). Use the `pivotPreviewColumns` property in [Layout Options](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) to set which *other* columns will be displayed in the table **Example: Pivot Layouts - Expand Cells** Opening a Pivot Cell to see full contents in Table View - This example shows how to expand a Pivot Cell to see Aggregated Values - It provides 4 different Layouts to show different combinations of Pivot Columns and Row Groups - In each Layout 2 columns are aggregated: `GitHub Stars` and `Github Watchers` - The 4 self-descriptive Layouts are: - `NO Pivot Cols - NO Row Groups` - `NO Pivot Cols - YES Row Groups` - `YES Pivot Cols - NO Row Groups` - `YES Pivot Cols - YES Row Groups` - We provided the `pivotPreviewColumns` property in [Layout Options](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) to add the `Name` column to the table that is generated - Switch between all 4 Layouts and in each one right-click on a Pivot Cell and select `Expand Aggregated Value` to see the different tables produced ```ts import { AdaptableOptions, PivotPreviewColumnsContext, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot Layouts Expand Cells', layoutOptions: { pivotPreviewColumns: (context: PivotPreviewColumnsContext) => { return ['name']; }, }, initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'NO Pivot Cols - NO Row Groups', Layouts: [ { Name: 'NO Pivot Cols - NO Row Groups', PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], PivotColumns: [], }, { Name: 'NO Pivot Cols - YES Row Groups', PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], PivotColumns: [], }, { Name: 'YES Pivot Cols - NO Row Groups', PivotColumns: ['license'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, { Name: 'YES Pivot Cols - YES Row Groups', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, ], }, }, }; ``` ```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'); }; ``` ## Total Rows and Columns Pivot Layouts (like Table Layouts) support [Grand Total Rows](https://www.adaptabletools.com/docs/handbook-aggregation-grand-total-row/index.md). These rows can be placed at top or bottom of the Grid, and display the total of all Aggregations. Additionally Pivots can be provided with [3 Pivot Total Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md) ## Server-Side Row Model All the examples in this section (like most on this site) use AG Grid's [Client Side Row Model](https://www.ag-grid.com/javascript-data-grid/client-side-model/#client-side-row-model). It is possible to access pivoting in AdapTable and AG Grid while using the [Server-Side Row Model](https://www.ag-grid.com/javascript-grid-server-side-model/). However it falls upon the developers to provide all the pivoted data themselves as well as the associated, often quite complex, logic. - This includes providing all the "dynamic" columns when a Column is pivoted - This is not a straightforward task and we recommend only using Server-Side Row Model when absolutely required See [Server-Side Row Model Developer Guide: Pivoting](https://www.adaptabletools.com/docs/dev-guide-row-models-server-pivoting/index.md) for full details and a working example --- # Pivot Column Groups Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-pivot-column-groups This AdapTable Help Page is a work in progress and will be completed in the next couple of days Pivot Column Groups are created dynamically by AG Grid when in pivot mode. One Column Group is created for each distinct value in the Pivot Column. - In the demo below 3 Pivot Columns Groups are created dynamically by AG Grid - e.g. one Pivot Column Group for each of the 3 values in the `Language` Column: HTML, JavaScript, TypeScript If there is more than one Pivot Column, Pivot Column Groups are created at each level of nesting. The demo below has a Pivot Column Group for each nested level (e.g. HTML/MIT License, JavaScript/MIT License etc) ## Expanding Column Groups By default AdapTable will display all the columns which are dynamically created by a Pivot Column. In other words, it will automatically expand, and display, all Pivot Column Groups. If this is not the desired behaviour, AdapTable offers 2 options to change this: - Setting Expanded / Collapsed Behavour for Pivot Columns Groups - Setting the Pivot Expand Level - These are **mutually exclusive** ways of setting Column Groups Expansion - Choose one or the other, but not both ### Expanded Collapsed Behaviour The expanded / collapsed behaviour for Pivot Column Groups can be configured in exactly the same way as for "normal" [Column Groups](https://www.adaptabletools.com/docs/handbook-grouping-columns/index.md); in other words they can be set in one of 4 ways: - to always open expanded - to always open collapsed - to open expanded by default (but with exceptions) - to open collapsed by default (but with exceptions) - Pivot Column Groups can only be Expanded or Collapsed if the Group is more than one level deep - In othere words, at least 2 Pivot Columns must be set See [Column Groups: Expanded / Collapsed Behaviour](https://www.adaptabletools.com/docs/handbook-grouping-columns-expanded-collapsed/index.md) for more information **Example: Pivot Column Groups: Expanded Collapsed** Configuring Expanded Collapsed Behaviour for Pivot Column Groups - This example contains 4 Layouts each of which show different options for Expanded / Collapsed Pivot Column Groups: - `Always Expanded` - all Pivot Column Groups are expanded (because ColumnGroupDefaultBehavior is set to `always-expanded`) - `Always Collapsed` - all Pivot Column Groups are collapsed (because ColumnGroupDefaultBehavior is set to `always-collapsed`) - `Collapsed Exceptions` - all Pivot Column Groups are collapsed with exception of `pivotGroup_language-license_HTML` (first group) - `Expanded Exceptions` - all Pivot Column Groups are expanded with exception of `pivotGroup_language-license_HTML` (first group) - Note: We have set 2 Pivot Columns (`Language` and `License`) which is why the Pivot Column Groups can be expanded or collapsed - In one of the 2 Exceptions Layouts, expand / collapse Pivot Column Groups, switch Layouts and then switch back - Note: the Exceptions have been saved, and are re-applied when the Layout loads ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot Column Groups: Expanded / Collapsed', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Always Expanded', Layouts: [ { Name: 'Always Expanded', PivotColumns: ['language', 'license'], PivotGroupedColumns: ['has_wiki'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, ], ColumnGroupValues: { ColumnGroupDefaultBehavior: 'always-expanded', }, }, { Name: 'Always Collapsed', PivotColumns: ['language', 'license'], PivotGroupedColumns: ['has_wiki'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, ], ColumnGroupValues: { ColumnGroupDefaultBehavior: 'always-collapsed', }, }, { Name: 'Expanded Exceptions', PivotColumns: ['language', 'license'], PivotGroupedColumns: ['has_wiki'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, ], ColumnGroupValues: { ColumnGroupDefaultBehavior: 'expanded', ExceptionGroupKeys: ['pivotGroup_language-license_HTML'], }, }, { Name: 'Collapsed Exceptions', PivotColumns: ['language', 'license'], PivotGroupedColumns: ['has_wiki'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, ], ColumnGroupValues: { ColumnGroupDefaultBehavior: 'collapsed', ExceptionGroupKeys: ['pivotGroup_language-license_HTML'], }, }, ], }, }, }; ``` ### Pivot Expand Level An alternative to setting the expanded / collapsed behaviour described above is to set the Expand Level. This is done via the `PivotExpandLevel` property in the Layout Definition, which can be used to configure these columns as follows: - -1 to expand all (the default behaviour) - 0 for no expanded Column Groups - 1 expand just the 1st level (and so on...) **Example: Expanding Pivot Columns** Pivot Layout with Expanded Pivot Columns configured - This example contains 2 Pivot Layout with default `PivotExpandLevel` settings: - `Pivot Layout Collapsed` - set to 0 and so we don't see the `Language` Column Groups - `Pivot Layout Expanded` - set to 1 and therefore we do see the `Language` Column Groups ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Expand Pivot Columns', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Layout Collapsed', Layouts: [ { Name: 'Pivot Layout Collapsed', PivotColumns: ['license', 'language'], PivotExpandLevel: 0, PivotGroupedColumns: ['has_wiki'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, { Name: 'Pivot Layout Expanded', PivotColumns: ['license', 'language'], PivotExpandLevel: 1, PivotGroupedColumns: ['has_wiki'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'github_watchers', AggFunc: 'sum', }, ], }, ], }, }, }; ``` ```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'); }; ``` --- # Defining Pivot Layouts Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-pivot-defining - Pivot Layouts enable AG Grid instances with Pivoting to be defined - All elements of pivoting are supported - Pivot Columns, Row Groups and Aggregations - Pivot Layouts can also include Format Column styles - Pivot Layouts can be defined at design-time through Initial Adaptable State, or created at runtime in the UI Wizard Pivot Layouts can be defined at design-time using [Pivot Layout Initial Adaptable State](https://www.adaptabletools.com/docs/handbook-layouts-pivot-technical-reference/index.md). ### Anatomy of an AdapTable Pivot Layout #### Base Properties [`PivotLayout`](https://www.adaptabletools.com/docs/reference/pivotlayout.md) object inherits from [`LayoutBase`](https://www.adaptabletools.com/docs/reference/layoutbase.md) (used also for Table Layouts) which contains these properties: | Property | Type | Description | | --- | --- | --- | | [AutoSizeColumns](https://www.adaptabletools.com/docs/reference/layoutbase.md#autosizecolumns) | `boolean` | Whether Columns should autosize when Layout first loads | | [ColumnFilters](https://www.adaptabletools.com/docs/reference/layoutbase.md#columnfilters) | [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md)`[]` | Collection of Column Filters to apply in Layout | | [ColumnGroupValues](https://www.adaptabletools.com/docs/reference/layoutbase.md#columngroupvalues) | [`ColumnGroupValues`](https://www.adaptabletools.com/docs/reference/columngroupvalues.md) | Defines which Column Groups are expanded / collapsed | | [ColumnHeaders](https://www.adaptabletools.com/docs/reference/layoutbase.md#columnheaders) | [`ColumnStringMap`](https://www.adaptabletools.com/docs/reference/columnstringmap.md) | Set of custom header names for some (or all) Columns | | [ColumnPinning](https://www.adaptabletools.com/docs/reference/layoutbase.md#columnpinning) | [`ColumnDirectionMap`](https://www.adaptabletools.com/docs/reference/columndirectionmap.md) | Details of which Columns are pinned | | [ColumnSizing](https://www.adaptabletools.com/docs/reference/layoutbase.md#columnsizing) | [`ColumnSizingMap`](https://www.adaptabletools.com/docs/reference/columnsizingmap.md) | Controls size (width or flex & min/max) for Columns | | [ColumnSorts](https://www.adaptabletools.com/docs/reference/layoutbase.md#columnsorts) | [`ColumnSort`](https://www.adaptabletools.com/docs/reference/columnsort.md)`[]` | Sorting to apply in the Layout | | [GrandTotalRow](https://www.adaptabletools.com/docs/reference/layoutbase.md#grandtotalrow) | `'top' \| 'bottom' \| 'pinnedTop' \| 'pinnedBottom' \| boolean` | Position of the Grand Total Row in the Layout | | [GridFilter](https://www.adaptabletools.com/docs/reference/layoutbase.md#gridfilter) | [`GridFilter`](https://www.adaptabletools.com/docs/reference/gridfilter.md) | Grid Filter to apply in Layout | | [Name](https://www.adaptabletools.com/docs/reference/layoutbase.md#name) | `string` | Name of the Layout as it appears in the Layout toolbar and tool panel | | [OpenCharts](https://www.adaptabletools.com/docs/reference/layoutbase.md#opencharts) | [`LayoutOpenChart`](https://www.adaptabletools.com/docs/reference/layoutopenchart.md)`[]` | AG Grid charts to open when this layout is selected (by chart UUID or name) | | [RowGroupDisplayType](https://www.adaptabletools.com/docs/reference/layoutbase.md#rowgroupdisplaytype) | `RowGroupDisplayType` | How Row Groups are displayed: 'single' - one hierarchical group Column; 'multi' - a separate group Column per Row Grouped Column; 'groupRows' - full-width group rows (no group column); defaults to 'single' | | [RowGroupValues](https://www.adaptabletools.com/docs/reference/layoutbase.md#rowgroupvalues) | [`RowGroupValues`](https://www.adaptabletools.com/docs/reference/rowgroupvalues.md) | Defines which Row Groups are expanded / collapsed | | [RowSelection](https://www.adaptabletools.com/docs/reference/layoutbase.md#rowselection) | [`LayoutRowSelection`](https://www.adaptabletools.com/docs/reference/layoutrowselection.md)` \| false` | Defines Row Selection behaviour for Layout; if false, Row Selection is disabled; if undefined, GridOptions is used | | [SuppressAggFuncInHeader](https://www.adaptabletools.com/docs/reference/layoutbase.md#suppressaggfuncinheader) | `boolean` | Hides the aggFunc in Column header: e.g. 'sum(Price)' becomes 'Price' | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/layoutbase.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | #### Pivot Properties The [`PivotLayout`](https://www.adaptabletools.com/docs/reference/pivotlayout.md) object additionally contains these properties which are specific to Pivot Layouts: | Property | Type | Description | | --- | --- | --- | | [PivotAggregationColumns](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotaggregationcolumns) | [`PivotAggregationColumns`](https://www.adaptabletools.com/docs/reference/pivotaggregationcolumns.md) | Columns showing aggregated values in Group Rows; 1st value in record is Column name, 2nd is either aggfunc (e.g. sum, avg etc.) or 'true' (to use default aggfunc) | | [PivotColumns](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotcolumns) | `string[]` | Mandatory list of Columns to pivot (provide empty array if just displaying Aggregations) | | [PivotColumnTotal](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotcolumntotal) | [`PivotTotalPosition`](https://www.adaptabletools.com/docs/reference/pivottotalposition.md) | Display automatically calculated Totals within EACH Pivot Column Group, in the position specified | | [PivotExpandLevel](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotexpandlevel) | `number` | How deep to expand Pivot Columns (0 for none, 1 for 1st level only etc, -1 to expand all) | | [PivotGrandTotal](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotgrandtotal) | [`PivotTotalPosition`](https://www.adaptabletools.com/docs/reference/pivottotalposition.md) | Display automatically calculated Totals of all Pivot Columns, in the position specified | | [PivotGroupedColumns](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotgroupedcolumns) | `string[]` | Columns which are row-grouped when the Layout is applied | | [PivotResultColumnsOrder](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotresultcolumnsorder) | `string[] \| boolean` | Ordered list of Pivot Result Columns; set to `true` to track current display order, or provide custom list | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/pivotlayout.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | The main properties required to create a Pivot Layout are: - `PivotColumns` - columns which generate a Pivot Column Group for each distinct column value - `PivotAggregationColumns` - columns which will display Aggregated Values (in Pivot Result Columns) - `PivotGroupedColumns` - columns that AG Grid will use for Row Grouping Developers can also provide `PivotGrandTotal` and `PivotColumnTotal` props which are used in [Pivot Total Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md) ### Defining a Pivot Layout These are the steps required to set up a standard Pivot Layout. To add Sorting, Pinning and other features see the relevant sections in the [Table Layout Guide](https://www.adaptabletools.com/docs/handbook-layouts-table/index.md). Choose something unique but relevant. This is how AdapTable will refer to the Layout in the UI `PivotColumns` is an array of (string) Column Ids. AG Grid dynamically creates a Pivot Result Column for each unique value in each Pivot Column, and each set is displayed in the order provided here. AdapTable **does not save** the actual Pivot Result Columns, since they are dynamically created, nor the order in which they are displayed If you do not require Pivot Columns, **provide an empty array**. `PivotGroupedColumns` is an array of (string) Column Ids. The Columns will be row-grouped in the order provided. Specify the [Row Group Expanded / Collapsed Behaviour](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md#expanded--collapsed-row-groups) as required. `PivotAggregationColumns` defines Aggregations to display It comprises an array of objects which contain 2 properties: - a `ColumnId` (string) - either an `aggFunc` (e.g. sum) or *true* (to use default `aggFunc`) Set the sizing for both Aggregation and Pivot Result Columns. `ColumnSizing` is a map where the ColumnId is the key, and an object (to define sizing, using either Widths or Flex) is the value. Alternatively use the `AutoSizeColumns` property to autosize all Layout Columns ```ts [[1, 18, "Name"],[2, 19, "PivotColumns"],[3, 20, "PivotGroupedColumns"],[3, 21, "RowGroupValues"],[4, 24, "PivotAggregationColumns"],[5, 34, "ColumnSizing"]] // 1. Provide a name ('Pivot Layout') // 2. Set 1 Column to be pivoted by AG Grid: // a. 'language' // 3. Set Row Grouping on 2 Columns: // a. 'license' // b. 'has_wiki' // 4. Provide Aggregations for 2 Columns // a. git_hub_stars - sum // b. github_watchers - count // 5. Define Column Widths on the 2 Aggregated Columns // a. github_watchers - 100 pixels // b. github_stars - 475 pixels const initialState: InitialState = { Layout: { CurrentLayout: 'Pivot Layout', Layouts: [ { Name: 'Pivot Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license', 'has_wiki'], RowGroupValues: { RowGroupDefaultBehavior: 'always-expanded', }, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'count', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSizing: { github_watchers: {Width: 475}, github_stars: {Width: 200}, }, }], }, } ``` ## Aggregation-Only Layouts Typically Pivot Layouts include one or more "Pivot Columns" and AG Grid creates a dynamic Pivot Result column for each unique permutation of Pivot Column value and Aggregation Column. However it is possible to create Pivot Layouts that **only contain Aggregated Columns** (and no Pivot Columns). When this happens AG Grid will still create a Pivot Result Column for each Aggregation Column but no Pivot Column Groups. When defining an Aggregation-only Pivot Layout, provide an **empty array** for the mandatory `pivotColumns` property ### Defining an Aggregation Only Pivot Layout Choose something unique but relevant. This is how AdapTable will refer to the Layout in the UI As you do not require Pivot Columns, **provide an empty array**. Provide Columns to be row-grouped using the `PivotGroupedColumns` property Define the Aggregations to display using the `PivotAggregationColumns` property. ```ts [[1, 9, "Name"],[2, 10, "PivotColumns"],[3, 11, "PivotGroupedColumns"],[4, 12, "PivotAggregationColumns"]] // 1. Set no Pivot Columns // 2. Set Row Grouping on license Column // 3. Provide Aggregations for git_hub_stars and github_watchers Columns const initialState: InitialState = { Layout: { CurrentLayout: 'Pivot Agg Only Layout', Layouts: [ { Name: 'Pivot Agg Only Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license', 'has_wiki'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'count', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, } ``` **Example: Pivot Aggregation Layouts** Pivot Layout with Agg Columns - This example creates a Pivot Layout which contains: - **no** PivotColumns - 2 PivotAggregationColumns - `Github Stars` & `Github Stars` (with `ColumnSizing` set for both columns, and `SuppressAggFuncInHeader` set to *true*) - 1 PivotGroupedColumn - `Language` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivoted Aggregation Layout', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Agg Layout', Layouts: [ { Name: 'Pivot Agg Layout', PivotGroupedColumns: ['language'], SuppressAggFuncInHeader: true, ColumnSizing: { github_watchers: {Width: 475}, github_stars: {Width: 200}, }, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], PivotColumns: [], // empty array required }, ], }, }, }; ``` ```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'); }; ``` --- # Filtering Pivot Layouts Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-pivot-filtering - Both Column Filters and the Grid Filter can be added to Pivot Layouts In AdapTable, [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) and the [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) are always associated with a specific Layout. - AdapTable provides very advanced Filtering with many configuration options and UI Components available - See the sections on [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) and the [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) for more details ## Column Filters Column Filters can be applied to any of the 3 main elements of a Pivot Layout: - Pivot Columns - Pivot Aggregation Columns - Pivot Row Grouped Columns ### Defining a Pivot Layout With Column Filters Add the main properties nearly all Pivot Layouts require Pivot Layouts can include [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) These can be added to any of the 3 main elements of a Pivot Layout: - PivotColumns - PivotGroupedColumns - PivotAggregationColumns ```ts [[2, 14, "ColumnFilters"]] // Provide Column Filters on 3 Columns // Github Stars - PivotAggregationColumn // Language - PivotColumn // License - PivotGroupedColumn const initialState: InitialState = { Layout: { CurrentLayout: 'Pivot Layout', Layouts: [ { Name: 'Pivot Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license'], PivotAggregationColumns: [{ ColumnId: 'github_stars', AggFunc: 'sum', }], ColumnFilters: [ { ColumnId: 'github_stars', // Pivot Aggregation Column Predicates: [{ PredicateId: 'GreaterThan', Inputs: ['5000']}] }, { ColumnId: 'language', // Pivot Column Predicates: [{ PredicateId: 'Contains', Inputs: ['Script']}], }, { ColumnId: 'license', // Pivot Grouped Column Predicates: [{ PredicateId: 'In', Inputs: ['MIT License', 'Other']}], }], }], }, } ``` ### Pivot Aggregation Columns Column Filters can be attached to Pivot Aggregation Columns and they will display normally. Additionally, AdapTable automatically applies the Aggregation Column filter to **all** associated dynamic Pivot Result Columns. In other words if you add a Filter to an aggregation column and then you create a Pivot Column, the Column Filter will be applied automatically to every Pivot Result Column that uses that aggregation. - You will only see the Filter details in the Aggregation Column but not in any derived Pivot Result Columns - This is because there is also the possibility to create Filters Directly on Pivot Result Columns - see below **Example: Pivot: Column Filtering** Applying Column Filtering when Pivoting - In this example we provide 2 Layouts which both have Filters applied: - `Pivot Aggregation Filter Layout` - has only aggregations and no Pivot Columns - and 2 Column Filters: - `Language` - a PivotGroupedColumn - `NotContains` "Script" - `GitHub Stars` - an Aggregation Column - `GreaterThan` 2000 - `Pivot Column Filter Layout` - has both aggregations and a Pivot Column (Language) - and 3 Column Filters: - `Language` - a PivotGroupedColumn - `NotContains` "Script" - `License` - a Pivot Column - In "MIT License", "Other" - `GitHub Stars` - an Aggregation Column - `GreaterThan` 2000 - Note: We see the details of the Filters in `Pivot Aggregation Filter Layout` as they are just Aggregations but not in the `Pivot Column Filter Layout` - In the `Pivot Column Filter Layout`, remove `Language` from Column Labels in Column Tool Panel (i.e. make it an *Aggregation Only* Layout) and note how `Github Stars` is directly filtered - Clear the Github Stars Column Filter in the Filters Toolbar in the Dashboard and note how the data changes ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot: Column Filtering', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout', 'ColumnFilter']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Aggregation Filter Layout', Layouts: [ { Name: 'Pivot Aggregation Filter Layout', PivotColumns: [''], PivotGroupedColumns: ['license'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnFilters: [ { ColumnId: 'language', Predicates: [ { PredicateId: 'NotContains', Inputs: ['Script'], }, ], }, { ColumnId: 'github_stars', Predicates: [ { PredicateId: 'GreaterThan', Inputs: [20000], }, ], }, ], }, { Name: 'Pivot Column Filter Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnFilters: [ { ColumnId: 'language', Predicates: [ { PredicateId: 'NotContains', Inputs: ['Script'], }, ], }, { ColumnId: 'license', Predicates: [ { PredicateId: 'In', Inputs: ['MIT License', 'Other'], }, ], }, { ColumnId: 'github_stars', Predicates: [ { PredicateId: 'GreaterThan', Inputs: [20000], }, ], }, ], }, ], }, }, }; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; export const onAdaptableReady = ({agGridApi}: AdaptableReadyInfo) => { agGridApi.openToolPanel('columns'); }; ``` ```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, }, autoGroupColumnDef: { floatingFilter: true, filter: 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', }, ], }, }; ``` ### Pivot Result Columns In the demo above we filtered on the Github Stars PivotAggregation Column, and that Column Filter was applied to all its associated Pivot Result Columns. However it is possible to filter only on specific, named, [Pivot Result Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-result-columns/index.md). This is done by configurig the Filter using AG Grid’s autogenerated ColumnId. Any Column Filters applied by Run-time users to a Pivot Result Column will be persisted using that `ColumnId` **Example: Pivot Result Columns: Filtering** Applying Column Filtering in Pivot Result Columns - In this example we have created 2 Column Filters on Pivot Result Columns in the Layout Definition (both using AG Grid's autogenerated `ColumnId`) - `pivot_language_HTML_github_stars` where it is `GreaterThan` 20,000 - `pivot_language_JavaScript_github_watchers` where it is `GreaterThan` 250 ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot Result Columns: Filtering', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout', 'ColumnFilter'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Layout', Layouts: [ { Name: 'Pivot Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnFilters: [ { ColumnId: 'pivot_language_JavaScript_github_watchers', Predicates: [ { PredicateId: 'GreaterThan', Inputs: [250], }, ], }, { ColumnId: 'pivot_language_HTML_github_stars', Predicates: [ { PredicateId: 'GreaterThan', Inputs: [20000], }, ], }, ], }, { TableColumns: [ 'name', 'language', 'github_stars', 'popularity', 'license', 'open_issues_count', 'created_at', 'has_wiki', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ## Grid Filter The [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) is a cross-column filter applied across the whole Grid. ### Defining a Pivot Layout With Grid Filter Add the 4 main properties nearly all Pivot Layouts require: - Name - PivotColumns - PivotGroupedColumns - PivotAggregationColumns Pivot Layouts can also include the Grid Filter. This is a Boolean Expression evaluated by AdapTableQL. ```ts [[2, 11, "GridFilter"]] // Provide a Grid Filter const initialState: InitialState = { Layout: { CurrentLayout: 'Pivot Layout', Layouts: [ { Name: 'Pivot Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license'], PivotAggregationColumns: [{ ColumnId: 'github_stars', AggFunc: 'sum', }], GridFilter: { Expression: '[currency]="EUR" OR [price] > 5000)', }, }], }, } ``` --- # Formatting Pivot Layouts Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-pivot-formatting - All the different types of Columns used when pivoting in AG Grid can be formatted and styled by AdapTable: - Aggregation Columns - Pivot Result Columns - Pivot Column Groups - Pivot Row Grouped Columns - Pivot Total Columns - It is also possible to exclude pivoting from a given Style or Display Format AdapTable ensures that [Column Formatting and Styling](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) work automatically when AG Grid pivoting is applied. Formatting is applied for all the different types of Columns created when Pivoting. ## Pivot Aggregation Columns Providing Formatting to an Aggregated Column will style not only that column but also each associated Pivot Result Column that is created for it. For example, if we provide a Format for a "Price" Column, that will be applied each time Price is displayed in the Grid as a Pivot Result Column (potentially multiple times based on the Pivoting applied). **Example: Pivot - Formatting Aggregation Columns** Adding Styles and Column Formatting to Pivot Aggregation Columns - This demo shows [Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) in Pivoting at its most basic. We apply 3 Format Columns definitions (2 with conditions): - A [Predicate Conditional Style](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) to render cells in the `Open Issues` column red with white font where they > 35 - An [Expression Conditional Style](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) to render cells in the `GitHub Stars` column yellow with brown font where they > 9,000 - A Light Blue Italic and Right Alignment [Formatting Style](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md) for the `GitHub Watchers` column - We add 3 Layouts and both Formats are fully applied in all of them - `Pivot Aggregation Layout` - which has Pivot Aggregations - `Github Stars` and `Github Watchers` - but no Pivot Columns (and so no Pivot Result Columns) - `Pivot Cols Layout` - we pivot on License which creates 3 sets of Pivot Results Columns - and the formats are applied accordingly - `Table Layout` - a standard Table Layout which displays the same Column Formats - Switch from the Standard to the Pivot Layout and see that the Format Columns are still applied - Note that the Standard Layout includes 3 Format Columns, while the Pivot Layout has 2 ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot - Formatting Aggregation Columns', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-github_stars', Rule: { BooleanExpression: '[github_stars]> 9000', }, Style: { BackColor: 'Yellow', ForeColor: 'Brown', }, Scope: { ColumnIds: ['github_stars'], }, }, { Name: 'formatColumn-open_issues_count', Rule: { Predicates: [ { PredicateId: 'GreaterThan', Inputs: [35], }, ], }, Style: { BackColor: 'Red', ForeColor: 'White', }, Scope: { ColumnIds: ['open_issues_count'], }, }, { Name: 'formatColumn-github_watchers', Style: { ForeColor: 'LightBlue', FontStyle: 'Italic', Alignment: 'Right', }, Scope: { ColumnIds: ['github_watchers'], }, }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Aggregation Layout', Layouts: [ { Name: 'Pivot Aggregation Layout', PivotColumns: [''], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'open_issues_count', AggFunc: 'sum', }, ], }, { Name: 'Pivot Cols Layout', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'open_issues_count', AggFunc: 'sum', }, ], }, { Name: 'Table Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'open_issues_count', 'updated_at', 'created_at', 'has_wiki', 'pushed_at', ], 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', }, ], }, }; ``` ## Pivot Result Columns [Pivot Result Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-result-columns/index.md) can individually be provided with specific, bespoke, Column Formatting. This is different to the example above where formatting applied on an aggregation column, automatically included all Pivot Result Columns. In order to do this, you will need to know the autogenerated id of the Column created by AG Grid. In practice run-time users create Format Columns in the UI on specific columns which are then persisted in the Layout **Example: Pivot - Formatting Result Columns** Applying Column Formatting and Styling to Pivot Result Columns - In this example we have created 2 [Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) on Pivot Result Columns in the Layout Definition (both using AG Grid's autogenerated `ColumnId`) - `pivot_language_HTML_github_watchers` has a [Number Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-number/index.md) with Prefix and Integer Digits - `pivot_language_JavaScript_github_stars` has a [Column Formatting Style](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md) applied - For this reason, unlike the demo above, the Format Columns can be seen in `Pivot Cols Layout` (but not `Pivot Aggregation Layout`) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot - Formatting Result Columns', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Cols Layout', Layouts: [ { Name: 'Pivot Aggregation Layout', PivotColumns: [''], PivotGroupedColumns: ['license'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, { Name: 'Pivot Cols Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-pivot_language_HTML_github_watchers', Scope: { ColumnIds: ['pivot_language_HTML_github_watchers'], }, DisplayFormat: { Formatter: 'NumberFormatter', Options: { FractionDigits: 1, Prefix: 'GS ', }, }, }, { Name: 'formatColumn-pivot_language_JavaScript_github_stars', Scope: { ColumnIds: ['pivot_language_JavaScript_github_stars'], }, Style: { BackColor: '#2966a8', ForeColor: 'yellow', Alignment: 'Center', }, }, ], }, }, }; ``` ## Pivot Columns Groups It is not possible to Format a specific pivot column group by name. In other words you cannot set Scope to a Column Group. Instead, you need to create a Format Column which includes each of the Pivot Result Columns in the Group. ## Pivot Row Grouped Columns It is also possible to Format the Pivot Row Grouped Column - the column created when row grouping in Pivoting. The way to do this is to set the Column Scope of the Format Column to be ‘ag-Grid-AutoColumn’. **Example: Pivot - Formatting Row Groups** Applying Column Formatting and Styling to Pivot Row Grouping Columns - We provide a style for the Grouped column of white font on brown background. - Click the "Update Layout" button to change the Row Grouped Column in the Layout and note that the Format Style is unchanged ```ts import { AdaptableButton, AdaptableOptions, DashboardButtonContext, Layout, } from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot - Formatting Row Groups', dashboardOptions: { customDashboardButtons: [ { label: 'Update Layout', buttonStyle: { tone: 'neutral', variant: 'outlined', }, onClick: ( _button: AdaptableButton, context: DashboardButtonContext ) => { const currenLayout: Layout = context.adaptableApi.layoutApi.getCurrentLayout(); const columnToGroup = currenLayout.PivotGroupedColumns?.includes( 'license' ) ? 'has_wiki' : 'license'; context.adaptableApi.layoutApi.updateCurrentLayout(layout => { layout.PivotGroupedColumns = [columnToGroup]; return layout; }); }, }, ], }, initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Layout', Layouts: [ { Name: 'Pivot Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], }, { TableColumns: [ 'name', 'language', 'github_stars', 'popularity', 'license', 'open_issues_count', 'created_at', 'has_wiki', ], RowGroupedColumns: ['license'], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-license', Scope: { ColumnIds: ['license'], }, Style: { BackColor: 'Purple', ForeColor: 'White', Alignment: 'Center', }, }, { Name: 'formatColumn-ag-Grid-AutoColumn', Scope: { ColumnIds: ['ag-Grid-AutoColumn'], }, Style: { BackColor: 'Brown', ForeColor: 'White', Alignment: 'Center', }, }, ], }, }, }; ``` ## Pivot Total Columns The specially generated Pivot Total Columns can also be formatted. See [Formatting Pivot Total Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md#formatting--styling) for detailed instructions ## Excluding Pivoting By default all relevant Formatting will appear in Pivot Layouts. It is possible to leverage, the `ExcludeGroupRows` option in the Format Column's `RowScope` property to exclude Pivot Layouts from a particular Format or Stlye. Set `ExcludeGroupRows` to *true* in the Format Column's `RowScope` property to exclude Pivot Layouts **Example: Excluding formatting from Pivot Layouts** Ensuring Styles are excluded from Pivot Layouts - This demo provides 2 Format Columns that we see in the Pivot Layout - on `GitHub Stars` and `GitHub Watchers` columns - However there is a 3rd Format Column (that sets `Open Issues` to Red) but as this has `ExcludeGroupRows` set to *true* it does not appear in the Pivot Layout - Switch from the Pivot to the Table Layout and see the Format Column for the `Open Issues` column ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot Exclude Formatting', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, FormatColumn: { FormatColumns: [ { Name: 'formatColumn-github_stars', Rule: { Predicates: [ { PredicateId: 'GreaterThan', Inputs: [9000], }, ], }, Style: { BackColor: 'Yellow', ForeColor: 'Brown', }, Scope: { ColumnIds: ['github_stars'], }, }, { Name: 'formatColumn-github_watchers', Style: { ForeColor: 'LightBlue', FontStyle: 'Italic', Alignment: 'Right', }, Scope: { ColumnIds: ['github_watchers'], }, }, { Name: 'formatColumn-open_issues_count', Style: { ForeColor: 'Red', }, Scope: { ColumnIds: ['open_issues_count'], }, RowScope: { ExcludeGroupRows: true, }, }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Layout', Layouts: [ { Name: 'Pivot Layout', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'open_issues_count', AggFunc: 'sum', }, ], }, { Name: 'Table Layout', TableColumns: [ 'name', 'github_stars', 'language', 'github_watchers', 'open_issues_count', 'updated_at', 'created_at', 'has_wiki', 'pushed_at', ], 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', }, ], }, }; ``` --- # Pivot Result Columns Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-pivot-result-columns - Pivot Result Columns are dynamically created by AG Grid when Pivot Layouts are rendered - Each Pivot Result Columns is a unique combination of Pivot Column value and Aggregation Column - AdapTable allows users to format, filter, sort and size Pivot Result Columns independently - AdapTable allows enables saving of Pivot Result Columns order, and reapplies the order when the Layout next loads Pivot Result Columns are the columns created dynamically by AG Grid when pivoting occurs. Each [AG Grid created Pivot Result Column](https://www.ag-grid.com/javascript-data-grid/pivoting-result-columns/) is the unique permutation of 2 values: - each distinct value in a Pivot Column - each Aggregation Column For instance if you Pivot on a column which has 3 distinct values, and you have 2 Aggregation columns, then 6 Pivot Result Columns will be created by AG Grid. If there are multiple Pivot Columns, then a Pivot Result Column is created for every unique permutation ## Generated Ids AG Grid will give each Pivot Result Column a unique Id. These Ids are what AdapTable uses to filter, sort, size and position Pivot Result Columns as seen below The generated Id is typically made up of 4 elements, each separated by an underscore: - the word "pivot" - the name of the pivot column - the pivot column's value - the name of the aggregation value For example, if you had a Pivot Column of `currency` (with 2 unique values of 'USD' and 'EUR') and 2 aggregation column of `price` and `amount`, the 4 dynamically generated columns would be: - `pivot_currency_USD_price` - `pivot_currency_EUR_price` - `pivot_currency_USD_amount` - `pivot_currency_EUR_amount` ## Referencing AdapTable uses the Ids dynamically generated by AG Grid to reference each Pivot Result Column. This allows the Pivot Result Columns to be individually referenced in the Layout. Pivot Result Columns can be uniquely identifed for the purposes of: - Column Formatting - Filtering - Sorting - Column Sizing For more details on each of these together with examples see the pages in this section on: - [Filtering](https://www.adaptabletools.com/docs/handbook-layouts-pivot-formatting/index.md#pivot-result-columns) - [Formatting](https://www.adaptabletools.com/docs/handbook-layouts-pivot-filtering/index.md#pivot-result-columns) - [Sizing](https://www.adaptabletools.com/docs/handbook-layouts-pivot-sizing/index.md#pivot-result-columns) - [Sorting](https://www.adaptabletools.com/docs/handbook-layouts-pivot-sorting/index.md#pivot-result-columns) ## Ordering AG Grid decides Pivot Result Column order based on the unique permutations at the time of their creation. This is **non-deterministic** because the values in a Pivot Column can change between application loads By default AdapTable will **not** save this order, which has 2 consequences: - users will see the order decided by AG Grid based on values available when Layout loads - any changes made by users are not persisted (and essentially overturned when the Layout next loads) Where this is not the desired behaviour, AdapTable provides an alternative. This is done by using the `PivotResultColumnsOrder` property which is available in each Layout. The property can be set to one of 3 values: | Value | Behaviour | | -------- | ---------------------------------------------------------------------------------- | | `false` | No changes to Pivot Result Column Order are saved (default value) | | `true` | Any changes to Pivot Result Column Order will be persisted and available on reload | | [string] | List of Column Ids for initial order (and any changes to that order are persisted) | **Example: Pivot Result Columns** Using Pivot Result Columns - This example shows how AdapTable Layouts can be configured at the per-Pivot Result Column Level, by setting some behaviours, including: - 3 different Formats for the different Github Stars columns (red, green and blue fonts respectively) - The `pivot_language_JavaScript_github_stars` Column is given its own sort order and a larger size - There are 3 different Layouts provided to show the different behaviours for Column Order based on the `PivotResultColumnsOrder` property: - `Default Order` - set to *false* so that it shows Pivot Result Columns in the order created by AG Grid, and no changes are persisted - `Tracked Order` - set to *true* so that it also shows Pivot Result Columns in the order created by AG Grid, but now changes are persisted - `Configured Order` - a default list is provided (of the 2 TypeScript columns first), and subsequent changes are persisted ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot Result Columns', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, FormatColumn: { FormatColumns: [ { Name: 'style-html-red', Scope: { ColumnIds: ['pivot_language_HTML_github_stars'], }, Style: { ForeColor: 'Red', }, }, { Name: 'style-html-green', Scope: { ColumnIds: ['pivot_language_JavaScript_github_stars'], }, Style: { ForeColor: 'Green', }, }, { Name: 'style-html-blue', Scope: { ColumnIds: ['pivot_language_TypeScript_github_stars'], }, Style: { ForeColor: 'Blue', }, }, ], }, Layout: { CurrentLayout: 'Default Order', Layouts: [ { Name: 'Default Order', PivotColumns: ['language'], PivotGroupedColumns: ['license'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'count', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSorts: [ { ColumnId: 'pivot_language_JavaScript_github_stars', SortOrder: 'Asc', }, ], ColumnSizing: { pivot_language_JavaScript_github_stars: {Width: 300}, }, SuppressAggFuncInHeader: true, AutoSizeColumns: true, }, { Name: 'Tracked Order', PivotColumns: ['language'], PivotGroupedColumns: ['license'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'count', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSorts: [ { ColumnId: 'pivot_language_JavaScript_github_stars', SortOrder: 'Asc', }, ], ColumnSizing: { pivot_language_JavaScript_github_stars: {Width: 300}, }, PivotResultColumnsOrder: true, AutoSizeColumns: true, SuppressAggFuncInHeader: true, }, { Name: 'Configured Order', PivotColumns: ['language'], PivotGroupedColumns: ['license'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'count', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSorts: [ { ColumnId: 'pivot_language_JavaScript_github_stars', SortOrder: 'Asc', }, ], ColumnSizing: { pivot_language_JavaScript_github_stars: {Width: 300}, }, SuppressAggFuncInHeader: true, PivotResultColumnsOrder: [ 'pivot_language_TypeScript_github_stars', 'pivot_language_TypeScript_github_watchers', ], AutoSizeColumns: true, }, ], }, }, }; ``` --- # Row Selection in Pivot Layouts Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-pivot-selecting - Full Row Selection capabilities are provided in Pivot Layouts Row Selection in Pivot Layouts is configured using the `RowSelection` property. This property - also used for Table Layouts - allows for very configurable control over how rows can be selected in the Layout. It includes creating a dedicated Selection Column with checkboxes for easy row selection. See [Row Selection in Table Layouts](https://www.adaptabletools.com/docs/handbook-layouts-table-row-selection/index.md) for full details, together with many demos, of the selection options **Example: Pivot Layouts: Row Selection** Row Selection in Pivot Layouts - - This example contains 2 Layouts each of which has a different values for the `RowSelection` object: - `Pivot Cols Layout` - has "standard" row selection - `Pivot Sum Layout` - has no Header Checkbox and allows row selection by clicking anywhere in the Row ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Table Layouts Row Selection Pivoting', initialState: { Dashboard: { ModuleButtons: ['Layout', 'SettingsPanel'], Tabs: [ { Name: 'Default', Toolbars: ['Layout'], }, ], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Cols Layout', Layouts: [ { Name: 'Pivot Cols Layout', PivotColumns: ['license'], PivotGroupedColumns: ['language'], PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'count', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSizing: { week_issue_change: {Width: 475}, }, RowSelection: { Mode: 'multiRow', Checkboxes: true, HeaderCheckbox: true, }, }, { Name: 'Pivot Sum Layout', PivotColumns: [], PivotGroupedColumns: ['license'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, { ColumnId: 'Total', AggFunc: 'sum', }, ], RowSelection: { Mode: 'multiRow', Checkboxes: true, HeaderCheckbox: false, EnableClickSelection: 'enableSelection', }, }, ], }, }, }; ``` --- # Sizing Pivot Layouts Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-pivot-sizing - The widths of Pivot Result Columns can be saved in a Pivot Layout Layout Column Sizing in Pivot Layouts is configured using the `ColumnSizing` property. This property - also used for Table Layouts - allows you set the width (or flex) for each Column in the Layout. Additionally you can set the Minumum Width, Maximum Width and Resizability of each Column. See [Table Layout Column Sizing](https://www.adaptabletools.com/docs/handbook-layouts-table-column-sizing/index.md) for an in-depth discussion of the objects used ## Pivot Aggregation Columns Pivot Aggregation Columns can easily be sized, and given either a Width or a Flex. **Example: Pivot Aggregation Columns: Widths** Setting & Saving Column Widths of Pivot Aggregation Columns - In this example we provide bespoke Column Widths of 350px for 2 Pivot Aggregation Columns in the Layout Definition - `Github Stars` and `Github Watchers` ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot Aggregation Columns: Saving Widths', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Layout', Layouts: [ { Name: 'Pivot Layout', PivotColumns: [], PivotGroupedColumns: ['language'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSizing: { github_watchers: {Width: 350}, github_stars: {Width: 350}, }, }, { TableColumns: [ 'name', 'language', 'github_stars', 'popularity', 'license', 'open_issues_count', 'created_at', 'has_wiki', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ## Pivot Result Columns AdapTable also allows you to define - and save - the widths of [Pivot Result Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-result-columns/index.md). AG Grid dynamically generates Pivot Result Columns for each unique permutation of Pivot Column value and Aggregation Column Saving Pivot Result Columns Widths is also done using the Layout's `ColumnSizing` property. **Example: Pivot Result Columns: Widths** Setting & Saving Column Widths of Pivot Result Columns - In this example we provide bespoke Column Widths for 2 Pivot Result Columns in the Layout Definition (both using AG Grid's autogenerated `ColumnId`) - `pivot_language_HTML_github_watchers` and `pivot_language_JavaScript_github_stars` are both given custom widths of 350px - Note: Although we have set the widths in the Layout, it is far more common for the User to set them in the UI (and for AdapTable to persist those changes) ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot Result Columns: Saving Widths', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Layout', Layouts: [ { Name: 'Pivot Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSizing: { pivot_language_HTML_github_watchers: {Width: 350}, pivot_language_JavaScript_github_stars: {Width: 350}, }, }, { TableColumns: [ 'name', 'language', 'github_stars', 'popularity', 'license', 'open_issues_count', 'created_at', 'has_wiki', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` --- # Sorting Pivot Layouts Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-pivot-sorting - Pivot Layouts can use the same sorting as Table Layouts - Both Aggregation Columns and Pivot Result Columns can be sorted - Custom sorting can be applied to Aggregation Columns in Pivot Layouts All Columns in the Pivot Layout can be sorted - and the sorted column persisted to AdapTable State. ## Aggregation Columns It is straightforward to set Sorting for standalone Pivot Aggregation Columns. This is done using the standard `ColumnSorts` property in the Layout. - Sorting a Pivot Aggregation Column will not sort that column when there are Pivot Result Columns - Instead each Pivot Result Column will need to be sorted individually (see below) **Example: Pivot Sorting: Aggregation Columns** Setting & Saving Column Sorting for Pivot Aggregation Columns - In this example we set Column Sorting for the 2 Pivot Aggregation Columns - `Github Stars` and `Github Watchers` - We have not provided any PivotColumns - so there are no dynamic Pivot Result Columns created ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot Aggregation Columns: Sorting', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Layout', Layouts: [ { Name: 'Pivot Layout', PivotColumns: [], PivotGroupedColumns: ['license'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSorts: [ { ColumnId: 'github_stars', SortOrder: 'Asc', }, { ColumnId: 'github_watchers', SortOrder: 'Desc', }, ], }, { TableColumns: [ 'name', 'language', 'github_stars', 'popularity', 'license', 'open_issues_count', 'created_at', 'has_wiki', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ## Pivot Result Columns It is also possible to sort [Pivot Result Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-result-columns/index.md) and save this configuration in the [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md). This is also done via the `ColumnSorts` property, by using the AG Grid generated colId for the Pivot Result Column. **Example: Pivot Sorting: Pivot Result Columns** Setting & Saving Column Sorting for Pivot Result Columns - In this example we set Column Sorting for 2 Pivot Result Columns in the Layout Definition (both using AG Grid's autogenerated `ColumnId`) - `pivot_language_HTML_github_stars` and `pivot_language_JavaScript_github_watchers` are sorted ascendingly ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot Result Columns: Sorting', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Layout', Layouts: [ { Name: 'Pivot Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSorts: [ { ColumnId: 'pivot_language_HTML_github_stars', SortOrder: 'Asc', }, { ColumnId: 'pivot_language_JavaScript_github_watchers', SortOrder: 'Asc', }, ], }, { TableColumns: [ 'name', 'language', 'github_stars', 'popularity', 'license', 'open_issues_count', 'created_at', 'has_wiki', ], Name: 'Standard Layout', AutoSizeColumns: true, }, ], }, }, }; ``` ## Custom Sorts AdapTable allow for bespoke sorting via [Custom Sort](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md). This is also available in Pivot Layouts, but only to Aggregation Columns (i.e. not to Pivot Result Columns). **Example: Pivot Sorting: Custom Sorts** Using Custom Sorts in Pivot Layout - In this example we provide a, slightly random and pointless, Custom Sort on the `Github Stars` Column - we sort in this order: 138066, 9752, 867801 - This Custom Sort is applied in Column Sort that we apply to that Column ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {WebFramework} from 'rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'id', adaptableId: 'Pivot Custom Sorting', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, CustomSort: { CustomSorts: [ { Name: 'customSort-github_stars', ColumnId: 'github_stars', SortedValues: [138066, 9752, 867801], }, { Name: 'customSort-pivot_language_JavaScript_github_watchers', ColumnId: 'pivot_language_JavaScript_github_watchers', SortedValues: [21751, 204, 3375], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Pivot Agg Layout', Layouts: [ { Name: 'Pivot Agg Layout', PivotColumns: [], PivotGroupedColumns: ['license'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSorts: [ { ColumnId: 'github_stars', SortOrder: 'Asc', }, ], }, { Name: 'Pivot Cols Layout', PivotColumns: ['language'], PivotGroupedColumns: ['license'], SuppressAggFuncInHeader: true, PivotAggregationColumns: [ { ColumnId: 'github_watchers', AggFunc: 'sum', }, { ColumnId: 'github_stars', AggFunc: 'sum', }, ], ColumnSorts: [ { ColumnId: 'pivot_language_JavaScript_github_watchers', SortOrder: 'Asc', }, ], }, ], }, }, }; ``` --- # Pivot Layout Technical Reference Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-pivot-technical-reference - Layout State enables Pivot Layouts to be configured See [General Layouts Technical Reference](https://www.adaptabletools.com/docs/handbook-layouts-technical-reference/index.md) for details on Layout Options and Layout API ## Layout State [`Layout State`](https://www.adaptabletools.com/docs/reference/layoutstate.md) contains a collection of Layouts and the Current Layout: | Property | Type | Description | | --- | --- | --- | | [CurrentLayout](https://www.adaptabletools.com/docs/reference/layoutstate.md#currentlayout) | `string` | Layout to be loaded when AdapTable starts (using `Name` property in Layout); if not provided the first Layout is used | | [Layouts](https://www.adaptabletools.com/docs/reference/layoutstate.md#layouts) | [`LayoutArray`](https://www.adaptabletools.com/docs/reference/layoutarray.md) | Collection of Layouts - can be Table or Pivot | ### Base Layout Object Pivot Layouts derive from the [`LayoutBase`](https://www.adaptabletools.com/docs/reference/layoutbase.md) object defined as follows: | Property | Type | Description | | --- | --- | --- | | [AutoSizeColumns](https://www.adaptabletools.com/docs/reference/layoutbase.md#autosizecolumns) | `boolean` | Whether Columns should autosize when Layout first loads | | [ColumnFilters](https://www.adaptabletools.com/docs/reference/layoutbase.md#columnfilters) | [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md)`[]` | Collection of Column Filters to apply in Layout | | [ColumnGroupValues](https://www.adaptabletools.com/docs/reference/layoutbase.md#columngroupvalues) | [`ColumnGroupValues`](https://www.adaptabletools.com/docs/reference/columngroupvalues.md) | Defines which Column Groups are expanded / collapsed | | [ColumnHeaders](https://www.adaptabletools.com/docs/reference/layoutbase.md#columnheaders) | [`ColumnStringMap`](https://www.adaptabletools.com/docs/reference/columnstringmap.md) | Set of custom header names for some (or all) Columns | | [ColumnPinning](https://www.adaptabletools.com/docs/reference/layoutbase.md#columnpinning) | [`ColumnDirectionMap`](https://www.adaptabletools.com/docs/reference/columndirectionmap.md) | Details of which Columns are pinned | | [ColumnSizing](https://www.adaptabletools.com/docs/reference/layoutbase.md#columnsizing) | [`ColumnSizingMap`](https://www.adaptabletools.com/docs/reference/columnsizingmap.md) | Controls size (width or flex & min/max) for Columns | | [ColumnSorts](https://www.adaptabletools.com/docs/reference/layoutbase.md#columnsorts) | [`ColumnSort`](https://www.adaptabletools.com/docs/reference/columnsort.md)`[]` | Sorting to apply in the Layout | | [GrandTotalRow](https://www.adaptabletools.com/docs/reference/layoutbase.md#grandtotalrow) | `'top' \| 'bottom' \| 'pinnedTop' \| 'pinnedBottom' \| boolean` | Position of the Grand Total Row in the Layout | | [GridFilter](https://www.adaptabletools.com/docs/reference/layoutbase.md#gridfilter) | [`GridFilter`](https://www.adaptabletools.com/docs/reference/gridfilter.md) | Grid Filter to apply in Layout | | [Name](https://www.adaptabletools.com/docs/reference/layoutbase.md#name) | `string` | Name of the Layout as it appears in the Layout toolbar and tool panel | | [OpenCharts](https://www.adaptabletools.com/docs/reference/layoutbase.md#opencharts) | [`LayoutOpenChart`](https://www.adaptabletools.com/docs/reference/layoutopenchart.md)`[]` | AG Grid charts to open when this layout is selected (by chart UUID or name) | | [RowGroupDisplayType](https://www.adaptabletools.com/docs/reference/layoutbase.md#rowgroupdisplaytype) | `RowGroupDisplayType` | How Row Groups are displayed: 'single' - one hierarchical group Column; 'multi' - a separate group Column per Row Grouped Column; 'groupRows' - full-width group rows (no group column); defaults to 'single' | | [RowGroupValues](https://www.adaptabletools.com/docs/reference/layoutbase.md#rowgroupvalues) | [`RowGroupValues`](https://www.adaptabletools.com/docs/reference/rowgroupvalues.md) | Defines which Row Groups are expanded / collapsed | | [RowSelection](https://www.adaptabletools.com/docs/reference/layoutbase.md#rowselection) | [`LayoutRowSelection`](https://www.adaptabletools.com/docs/reference/layoutrowselection.md)` \| false` | Defines Row Selection behaviour for Layout; if false, Row Selection is disabled; if undefined, GridOptions is used | | [SuppressAggFuncInHeader](https://www.adaptabletools.com/docs/reference/layoutbase.md#suppressaggfuncinheader) | `boolean` | Hides the aggFunc in Column header: e.g. 'sum(Price)' becomes 'Price' | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/layoutbase.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | ### Pivot Layout Object The [`Pivot Layout`](https://www.adaptabletools.com/docs/reference/pivotlayout.md) additionally has: | Property | Type | Description | | --- | --- | --- | | [PivotAggregationColumns](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotaggregationcolumns) | [`PivotAggregationColumns`](https://www.adaptabletools.com/docs/reference/pivotaggregationcolumns.md) | Columns showing aggregated values in Group Rows; 1st value in record is Column name, 2nd is either aggfunc (e.g. sum, avg etc.) or 'true' (to use default aggfunc) | | [PivotColumns](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotcolumns) | `string[]` | Mandatory list of Columns to pivot (provide empty array if just displaying Aggregations) | | [PivotColumnTotal](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotcolumntotal) | [`PivotTotalPosition`](https://www.adaptabletools.com/docs/reference/pivottotalposition.md) | Display automatically calculated Totals within EACH Pivot Column Group, in the position specified | | [PivotExpandLevel](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotexpandlevel) | `number` | How deep to expand Pivot Columns (0 for none, 1 for 1st level only etc, -1 to expand all) | | [PivotGrandTotal](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotgrandtotal) | [`PivotTotalPosition`](https://www.adaptabletools.com/docs/reference/pivottotalposition.md) | Display automatically calculated Totals of all Pivot Columns, in the position specified | | [PivotGroupedColumns](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotgroupedcolumns) | `string[]` | Columns which are row-grouped when the Layout is applied | | [PivotResultColumnsOrder](https://www.adaptabletools.com/docs/reference/pivotlayout.md#pivotresultcolumnsorder) | `string[] \| boolean` | Ordered list of Pivot Result Columns; set to `true` to track current display order, or provide custom list | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/pivotlayout.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | ### Column Filter The `ColumnFilters` property is a collection of [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md) objects defined as follows: | Property | Type | Description | | --- | --- | --- | | [ColumnId](https://www.adaptabletools.com/docs/reference/columnfilter.md#columnid) | `string` | Column where Filter should be applied | | [Expression](https://www.adaptabletools.com/docs/reference/columnfilter.md#expression) | `string` | AdaptableQL boolean expression evaluated for each row, e.g. | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/columnfilter.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | [IsSuspended](https://www.adaptabletools.com/docs/reference/columnfilter.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object | ### Grid Filter The [`GridFilter`](https://www.adaptabletools.com/docs/reference/gridfilter.md) object is defined as follows: | Property | Type | Description | | --- | --- | --- | | [Expression](https://www.adaptabletools.com/docs/reference/gridfilter.md#expression) | `string` | The (boolean) Expression to run | | [IsReadOnly](https://www.adaptabletools.com/docs/reference/gridfilter.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') | | [IsSuspended](https://www.adaptabletools.com/docs/reference/gridfilter.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object | ### Column Sort The [`ColumnSort`](https://www.adaptabletools.com/docs/reference/columnsort.md) object used for sorting is defined as follows: | Property | Type | Description | | --- | --- | --- | | [ColumnId](https://www.adaptabletools.com/docs/reference/columnsort.md#columnid) | `string` | Id of Column being sorted | | [SortOrder](https://www.adaptabletools.com/docs/reference/columnsort.md#sortorder) | `'Asc' \| 'Desc'` | How Column is sorted - either 'Asc' or 'Desc' | ### Row Selection The [`LayoutRowSelection`](https://www.adaptabletools.com/docs/reference/layoutrowselection.md) object used for row selection is defined as follows: | Property | Type | Description | Default | | --- | --- | --- | --- | | [Checkboxes](https://www.adaptabletools.com/docs/reference/layoutrowselection.md#checkboxes) | `boolean` | Whether to display checkboxes in Selection Column | true | | [CheckboxInGroupColumn](https://www.adaptabletools.com/docs/reference/layoutrowselection.md#checkboxingroupcolumn) | `boolean` | Renders selection checkboxes in Auto-Group Column (if `true`) or in dedicated Selection Column (if `false`) | false | | [EnableClickSelection](https://www.adaptabletools.com/docs/reference/layoutrowselection.md#enableclickselection) | `boolean \| 'enableDeselection' \| 'enableSelection'` | Selection behaviour when clicking a row: 'enableSelection' \| 'enableDeselection' \| true \| false | false | | [GroupSelectMode](https://www.adaptabletools.com/docs/reference/layoutrowselection.md#groupselectmode) | `GroupSelectionMode` | Grouping Select Mode: 'self' \| 'descendants' \| 'filteredDescendants' | 'self' | | [HeaderCheckbox](https://www.adaptabletools.com/docs/reference/layoutrowselection.md#headercheckbox) | `boolean` | Whether to show checkbox in Header of Selection Column Header ('multiRow' only) | true | | [Mode](https://www.adaptabletools.com/docs/reference/layoutrowselection.md#mode) | `'singleRow' \| 'multiRow'` | Row Selection Mode: 'singleRow' or 'multiRow' | | | [SelectAllMode](https://www.adaptabletools.com/docs/reference/layoutrowselection.md#selectallmode) | `SelectAllMode` | Select All Mode: 'all' \| 'filtered' \| 'currentPage' | 'all' | ### Other Pivot Layout Properties | Property | Type | | ------------------- | -------------------------------------------------------------------- | | `ColumnPinning` | [`ColumnDirectionMap`](https://www.adaptabletools.com/docs/reference/columndirectionmap.md) | | `ColumnSizing` | [`ColumnSizingMap`](https://www.adaptabletools.com/docs/reference/columnsizingmap.md) | | `ColumnHeaders` | [`ColumnStringMap`](https://www.adaptabletools.com/docs/reference/columnstringmap.md) | | `RowGroupValues` | [`RowGroupValues`](https://www.adaptabletools.com/docs/reference/rowgroupvalues.md) | | `ColumnGroupValues` | [`ColumnGroupValues`](https://www.adaptabletools.com/docs/reference/columngroupvalues.md) | - `RowGroupValues` contains exceptions of type [`RowGroupValuesWithExceptionKeys`](https://www.adaptabletools.com/docs/reference/rowgroupvalueswithexceptionkeys.md) - `ColumnGroupValues` contains exceptions of type [`ColumnGroupValuesWithExceptionKeys`](https://www.adaptabletools.com/docs/reference/columngroupvalueswithexceptionkeys.md) --- # Pivot Total Columns Canonical page: https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns - AdapTable provides 3 Pivot Total Columns: - Pivot Grand Total - Pivot Column Total - Pivot Aggregation Total AdapTable provides Pivot Total Columns for use in AG Grid pivoting. These are special columns which allow users to analyze data through different levels of aggregation. There are 3 different types of Pivot Total Columns available, all of which can be defined, customised and positioned before or after the associated pivot data. | Column | Description | | ----------------------- | --------------------------------------------------------------------------- | | Pivot Grand Total | Provides a summary view of all pivot data | | Pivot Column Total | Inserts subtotal columns for each Pivot Column Group | | Pivot Aggregation Total | Totals each Pivot Result column value in each Pivot Column Group separately | Pivot Column Totals **cannot be combined** with Pivot Aggregation Total Columns in the same Layout In addition, AdapTable provides [Grand Total Rows](https://www.adaptabletools.com/docs/handbook-aggregation-grand-total-row/index.md) which display the totals for all Aggregated Cells ## Pivot Grand Total Pivot Grand Total Columns provide a summary view of all pivot aggregation data. One Pivot Grand Total Column is displayed for each Aggregation Column defined in the Pivot Layout, showing the total aggregation for that column. The Column calculates totals using the specified aggregation function for each column independently **Example: Pivot Grand Totals** Pivot Grand Total Columns - This example contains 2 Layouts which each contain aggregations for the Gold, Silver and Bronze columns - Both Layouts are configured to display a Pivot Grand Total Column, so that 3 are provided in total, one for each aggregation - The `Grand Total Before` Layout displays the Pivot Grand Totals before the Pivot Result Columns, and the `Grand Total After` shows it at the end ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {IOlympicData} from './rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'athlete', adaptableId: 'Pivot Grand Total', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Grand Total Before', Layouts: [ { Name: 'Grand Total Before', PivotColumns: ['sport', 'year'], PivotGroupedColumns: ['country'], PivotGrandTotal: 'before', PivotAggregationColumns: [ { ColumnId: 'gold', AggFunc: 'sum', }, { ColumnId: 'silver', AggFunc: 'sum', }, { ColumnId: 'bronze', AggFunc: 'sum', }, ], }, { Name: 'Grand Total After', PivotColumns: ['sport', 'year'], PivotGroupedColumns: ['country'], PivotGrandTotal: 'after', PivotAggregationColumns: [ { ColumnId: 'gold', AggFunc: 'sum', }, { ColumnId: 'silver', AggFunc: 'sum', }, { ColumnId: 'bronze', AggFunc: 'sum', }, ], }, ], }, }, }; ``` ```ts import {ColDef} from 'ag-grid-enterprise'; export const columnDefs: ColDef[] = [ { field: 'id', cellDataType: 'number', hide: true, lockVisible: true, suppressFiltersToolPanel: true, suppressColumnsToolPanel: true, }, {field: 'country', cellDataType: 'text', enableRowGroup: true}, {field: 'athlete', cellDataType: 'text', enableRowGroup: true}, {field: 'sport', cellDataType: 'text', enablePivot: true}, {field: 'year', cellDataType: 'number', enablePivot: true}, {field: 'gold', cellDataType: 'number', enableValue: true}, {field: 'silver', cellDataType: 'number', enableValue: true}, {field: 'bronze', cellDataType: 'number', enableValue: true}, {field: 'age', cellDataType: 'number'}, {field: 'date', cellDataType: 'date'}, {field: 'total', cellDataType: 'number'}, ]; ``` ```ts import {ColDef, GridOptions, themeBalham} from 'ag-grid-enterprise'; import {IOlympicData} from './rowData'; import {columnDefs} from './columnDefs'; export const gridOptions: GridOptions = { theme: themeBalham, defaultColDef: { resizable: true, sortable: true, editable: 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 export interface IOlympicData { athlete: string; age: number; country: string; year: number; date: string; sport: string; gold: number; silver: number; bronze: number; total: number; } export const getRowData = (limit?: number) => { const rawData = limit ? rowData.slice(0, limit) : rowData; return rawData.map((item, index) => ({...item, id: index})); }; export const rowData: IOlympicData[] = [ { athlete: 'Michael Phelps', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 8, silver: 0, bronze: 0, total: 8, }, { athlete: 'Michael Phelps', age: 19, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 6, silver: 0, bronze: 2, total: 8, }, { athlete: 'Michael Phelps', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 4, silver: 2, bronze: 0, total: 6, }, { athlete: 'Natalie Coughlin', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 2, bronze: 3, total: 6, }, { athlete: 'Aleksey Nemov', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 2, silver: 1, bronze: 3, total: 6, }, { athlete: 'Alicia Coutts', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 3, bronze: 1, total: 5, }, { athlete: 'Missy Franklin', age: 17, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 4, silver: 0, bronze: 1, total: 5, }, { athlete: 'Ryan Lochte', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 2, bronze: 1, total: 5, }, { athlete: 'Allison Schmitt', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 3, silver: 1, bronze: 1, total: 5, }, { athlete: 'Natalie Coughlin', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 2, silver: 2, bronze: 1, total: 5, }, { athlete: 'Ian Thorpe', age: 17, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 3, silver: 2, bronze: 0, total: 5, }, { athlete: 'Dara Torres', age: 33, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 3, total: 5, }, { athlete: 'Cindy Klassen', age: 26, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 2, bronze: 2, total: 5, }, { athlete: 'Nastia Liukin', age: 18, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 3, bronze: 1, total: 5, }, { athlete: 'Marit Bjørgen', age: 29, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 3, silver: 1, bronze: 1, total: 5, }, { athlete: 'Sun Yang', age: 20, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 1, total: 4, }, { athlete: 'Kirsty Coventry', age: 24, country: 'Zimbabwe', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 3, bronze: 0, total: 4, }, { athlete: 'Libby Lenton-Trickett', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 1, bronze: 1, total: 4, }, { athlete: 'Ryan Lochte', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 2, total: 4, }, { athlete: 'Inge de Bruijn', age: 30, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 2, total: 4, }, { athlete: 'Petria Thomas', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 3, silver: 1, bronze: 0, total: 4, }, { athlete: 'Ian Thorpe', age: 21, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 2, silver: 1, bronze: 1, total: 4, }, { athlete: 'Inge de Bruijn', age: 27, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 3, silver: 1, bronze: 0, total: 4, }, { athlete: 'Gary Hall Jr.', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 1, bronze: 1, total: 4, }, { athlete: 'Michael Klim', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 2, bronze: 0, total: 4, }, { athlete: "Susie O'Neill", age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 3, bronze: 0, total: 4, }, { athlete: 'Jenny Thompson', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 3, silver: 0, bronze: 1, total: 4, }, { athlete: 'Pieter van den Hoogenband', age: 22, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 2, total: 4, }, { athlete: 'An Hyeon-Su', age: 20, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 3, silver: 0, bronze: 1, total: 4, }, { athlete: 'Aliya Mustafina', age: 17, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 2, total: 4, }, { athlete: 'Shawn Johnson', age: 16, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 3, bronze: 0, total: 4, }, { athlete: 'Dmitry Sautin', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 1, bronze: 2, total: 4, }, { athlete: 'Leontien Zijlaard-van Moorsel', age: 30, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 3, silver: 1, bronze: 0, total: 4, }, { athlete: 'Petter Northug Jr.', age: 24, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 2, silver: 1, bronze: 1, total: 4, }, { athlete: 'Ole Einar Bjørndalen', age: 28, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 4, silver: 0, bronze: 0, total: 4, }, { athlete: 'Janica Kostelic', age: 20, country: 'Croatia', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 3, silver: 1, bronze: 0, total: 4, }, { athlete: 'Nathan Adrian', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Yannick Agnel', age: 20, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Brittany Elmslie', age: 18, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Matt Grevers', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Ryosuke Irie', age: 22, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Cullen Jones', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Ranomi Kromowidjojo', age: 21, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Camille Muffat', age: 22, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Mel Schlanger', age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Emily Seebohm', age: 20, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Rebecca Soni', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Satomi Suzuki', age: 21, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Dana Vollmer', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Alain Bernard', age: 25, country: 'France', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'László Cseh Jr.', age: 22, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 3, bronze: 0, total: 3, }, { athlete: 'Matt Grevers', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Margaret Hoelzer', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Katie Hoff', age: 19, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Leisel Jones', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Kosuke Kitajima', age: 25, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Andrew Lauterstein', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Jason Lezak', age: 32, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Pang Jiaying', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Aaron Peirsol', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Steph Rice', age: 20, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Jess Schipper', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Rebecca Soni', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Eamon Sullivan', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Dara Torres', age: 41, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 3, bronze: 0, total: 3, }, { athlete: 'Amanda Beard', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Antje Buschschulte', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 3, total: 3, }, { athlete: 'Kirsty Coventry', age: 20, country: 'Zimbabwe', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Ian Crocker', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Grant Hackett', age: 24, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Brendan Hansen', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Jodie Henry', age: 20, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Otylia Jedrzejczak', age: 20, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Leisel Jones', age: 18, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Kosuke Kitajima', age: 21, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Laure Manaudou', age: 17, country: 'France', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Aaron Peirsol', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Kaitlin Sandeno', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Roland Schoeman', age: 24, country: 'South Africa', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Pieter van den Hoogenband', age: 26, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Therese Alshammar', age: 23, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Yana Klochkova', age: 18, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Lenny Krayzelburg', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Massimiliano Rosolino', age: 22, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Petria Thomas', age: 25, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Matt Welsh', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Lee Jeong-Su', age: 20, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Apolo Anton Ohno', age: 27, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Wang Meng', age: 24, country: 'China', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Jin Seon-Yu', age: 17, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Lee Ho-Seok', age: 19, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Apolo Anton Ohno', age: 23, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Wang Meng', age: 20, country: 'China', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Marc Gagnon', age: 26, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Yang Yang (A)', age: 25, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Stephanie Beckert', age: 21, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Martina Sáblíková', age: 22, country: 'Czech Republic', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Enrico Fabris', age: 24, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Chad Hedrick', age: 28, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Jochem Uytdehaage', age: 25, country: 'Netherlands', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Sabine Völker', age: 28, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Gregor Schlierenzauer', age: 20, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Lars Bystøl', age: 27, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Johnny Spillane', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 0, silver: 3, bronze: 0, total: 3, }, { athlete: 'Felix Gottwald', age: 30, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Georg Hettich', age: 27, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Felix Gottwald', age: 26, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 3, total: 3, }, { athlete: 'Samppa Lajunen', age: 22, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Aly Raisman', age: 18, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Kohei Uchimura', age: 23, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Zou Kai', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Cheng Fei', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Yang Wei', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Yang Yilin', age: 15, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Zou Kai', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Marian Dragulescu', age: 23, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Paul Hamm', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Carly Patterson', age: 16, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Catalina Ponor', age: 16, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Simona Amânar', age: 20, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Svetlana Khorkina', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Yekaterina Lobaznyuk', age: 17, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Yelena Zamolodchikova', age: 17, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Guo Shuang', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Chris Hoy', age: 32, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Bradley Wiggins', age: 24, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Florian Rousseau', age: 26, country: 'France', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Justyna Kowalczyk', age: 27, country: 'Poland', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Johan Olsson', age: 29, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Stefania Belmondo', age: 33, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Yuliya Chepalova', age: 25, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Frode Estil', age: 29, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Bente Skari-Martinsen', age: 29, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Magdalena Neuner', age: 23, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Emil Hegle Svendsen', age: 24, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Albina Akhatova', age: 29, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Ole Einar Bjørndalen', age: 32, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Sven Fischer', age: 34, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Martina Glagow-Beck', age: 26, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 3, bronze: 0, total: 3, }, { athlete: 'Michael Greis', age: 29, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Kati Wilhelm', age: 29, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Kati Wilhelm', age: 25, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Yohan Blake', age: 22, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Usain Bolt', age: 25, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Allyson Felix', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Shelly-Ann Fraser-Pryce', age: 25, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Carmelita Jeter', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Usain Bolt', age: 21, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Veronica Campbell-Brown', age: 22, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Justin Gatlin', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Bode Miller', age: 32, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Aksel Lund Svindal', age: 27, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Anja Pärson', age: 24, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Stephan Eberharter', age: 32, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Ding Ning', age: 22, country: 'China', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Feng Tian Wei', age: 25, country: 'Singapore', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Li Xiaoxia', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Dmitrij Ovtcharov', age: 23, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Wang Hao', age: 28, country: 'China', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Zhang Jike', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Guo Yue', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Ma Lin', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Wang Hao', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Wang Liqin', age: 30, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Wang Nan', age: 29, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Zhang Yining', age: 26, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Zhang Yining', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Kong Linghui', age: 24, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Li Ju', age: 24, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Liu Guoliang', age: 24, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Wang Nan', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Viktoriya Azarenko', age: 22, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Mike Bryan', age: 34, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Andy Murray', age: 25, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Serena Williams', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Fernando González', age: 24, country: 'Chile', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Nicolás Massú', age: 26, country: 'Chile', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Venus Williams', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ona Carbonell', age: 22, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Andrea Fuentes', age: 29, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Huang Xuechen', age: 22, country: 'China', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Nataliya Ishchenko', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Liu Ou', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Svetlana Romashina', age: 22, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Anastasiya Davydova', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Andrea Fuentes', age: 25, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Gemma Mengual', age: 31, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Anastasiya Yermakova', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Alison Bartosik', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Anastasiya Davydova', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Anna Kozlova', age: 31, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Miya Tachibana', age: 29, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Miho Takeda', age: 27, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Anastasiya Yermakova', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Olga Brusnikina', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Mariya Kiselyova', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Miya Tachibana', age: 25, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Miho Takeda', age: 24, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Becky Adlington', age: 23, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Bronte Barratt', age: 23, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Elizabeth Beisel', age: 19, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Mireia Belmonte', age: 21, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Ricky Berens', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Aleksandra Gerasimenya', age: 26, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Brendan Hansen', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Jessica Hardy', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Chad le Clos', age: 20, country: 'South Africa', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Clément Lefert', age: 24, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Amaury Leveaux', age: 26, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'James Magnussen', age: 21, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Takeshi Matsuda', age: 28, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Oussama Mellouli', age: 28, country: 'Tunisia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Park Tae-Hwan', age: 22, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Christian Sprenger', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Jeremy Stravius', age: 24, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Aya Terakawa', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Nick Thoman', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Marleen Veldhuis', age: 33, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Ye Shiwen', age: 16, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Becky Adlington', age: 19, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Leith Brodie', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Cate Campbell', age: 16, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'César Cielo Filho', age: 21, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Hugues Duboscq', age: 26, country: 'France', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Felicity Galvez', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Grant Hackett', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Kara Lynn Joyce', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Amaury Leveaux', age: 22, country: 'France', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Christine Magnuson', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Patrick Murphy', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Park Tae-Hwan', age: 18, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Shayne Reese', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Brenton Rickard', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Mel Schlanger', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Julia Smit', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Britta Steffen', age: 24, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Hayden Stoeckel', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Matt Targett', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Peter Vanderkaay', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Arkady Vyachanin', age: 24, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Garrett Weber-Gale', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Lindsay Benko', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Gary Hall Jr.', age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Brooke Hanson', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kara Lynn Joyce', age: 18, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Klete Keller', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Yana Klochkova', age: 22, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Rachel Komisarz', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Libby Lenton-Trickett', age: 19, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Jason Lezak', age: 28, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Ryan Lochte', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Alice Mills', age: 18, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Tomomi Morita', age: 19, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Markus Rogan', age: 22, country: 'Austria', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Jenny Thompson', age: 31, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Franziska van Almsick', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Neil Walker', age: 28, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Amanda Weir', age: 18, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Takashi Yamamoto', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Brooke Bennett', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Beatrice Coada-Caslaru', age: 25, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Josh Davis', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Tom Dolan', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Anthony Ervin', age: 19, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Domenico Fioravanti', age: 23, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Grant Hackett', age: 20, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Geoff Huegill', age: 21, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Leisel Jones', age: 15, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Klete Keller', age: 18, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Jason Lezak', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Diana Mocanu', age: 16, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Martina Moravcová', age: 24, country: 'Slovakia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Ed Moses', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Diana Munz', age: 18, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Mai Nakamura', age: 21, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Todd Pearson', age: 22, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Adam Pine', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Claudia Poll', age: 27, country: 'Costa Rica', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Megan Quann-Jendrick', age: 16, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Giaan Rooney', age: 17, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Courtney Shealy', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ashley Tappin', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Stev Theloke', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Amy Van Dyken', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Neil Walker', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'J. R. Celski', age: 19, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Charles Hamelin', age: 25, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Lee Ho-Seok', age: 23, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Park Seung-Hui', age: 17, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Katherine Reutter', age: 21, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Seong Si-Baek', age: 22, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Marianne St-Gelais', age: 19, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'François-Louis Tremblay', age: 29, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Zhou Yang', age: 18, country: 'China', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Choi Eun-Gyeong', age: 21, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Anouk Leblanc-Boucher', age: 21, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'François-Louis Tremblay', age: 25, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Choi Eun-Gyeong', age: 17, country: 'South Korea', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Go Gi-Hyeon', age: 15, country: 'South Korea', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Jonathan Guilmette', age: 23, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Li Jiajun', age: 26, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Apolo Anton Ohno', age: 19, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Evgeniya Radanova', age: 24, country: 'Bulgaria', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Mathieu Turcotte', age: 25, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Wang Chunlu', age: 23, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Yang Yang (S)', age: 24, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Shani Davis', age: 27, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kristina Groves', age: 33, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Chad Hedrick', age: 32, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Sven Kramer', age: 23, country: 'Netherlands', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Lee Seung-Hun', age: 21, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Mo Tae-Beom', age: 21, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Ivan Skobrev', age: 27, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Mark Tuitert', age: 29, country: 'Netherlands', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Joey Cheek', age: 26, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Shani Davis', age: 23, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Anni Friesinger-Postma', age: 29, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Kristina Groves', age: 29, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Clara Hughes', age: 33, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Sven Kramer', age: 19, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Claudia Pechstein', age: 33, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Carl Verheijen', age: 30, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Erben Wennemars', age: 30, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Ireen Wüst', age: 19, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Derek Parra', age: 31, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Claudia Pechstein', age: 29, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Jennifer Rodriguez', age: 25, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Simon Ammann', age: 28, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Adam Malysz', age: 32, country: 'Poland', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Matti Hautamäki', age: 24, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Andreas Kofler', age: 21, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Roar Ljøkelsøy', age: 29, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Thomas Morgenstern', age: 19, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Simon Ammann', age: 20, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Sven Hannawald', age: 27, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Matti Hautamäki', age: 20, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Adam Malysz', age: 24, country: 'Poland', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Niccolò Campriani', age: 24, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Jin Jong-O', age: 32, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Olena Kostevych', age: 27, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Jin Jong-O', age: 28, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Katerina Kurková-Emmons', age: 24, country: 'Czech Republic', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Lyubov Galkina', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Mariya Grozdeva', age: 32, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Lee Bo-Na', age: 23, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Mikhail Nestruyev', age: 35, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Igor Basinsky', age: 37, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Tao Luna', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kim Crow', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Georgeta Damian-Andrunache', age: 32, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Viorica Susanu', age: 32, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Georgeta Damian-Andrunache', age: 28, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Viorica Susanu', age: 28, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Georgeta Damian-Andrunache', age: 24, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Doina Ignat', age: 31, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Pieta van Dishoeck', age: 28, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Eeke van Nes', age: 31, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Bill Demong', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Bernhard Gruber', age: 27, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Magnus Moan', age: 22, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Ronny Ackermann', age: 24, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Jaakko Tallus', age: 20, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Denis Ablyazin', age: 19, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Chen Yibing', age: 27, country: 'China', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Gabby Douglas', age: 16, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Feng Zhe', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Sandra Izbasa', age: 22, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Viktoriya Komova', age: 17, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'McKayla Maroney', age: 16, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Marcel Nguyen', age: 24, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Mariya Paseka', age: 17, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Catalina Ponor', age: 24, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Louis Smith', age: 23, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Max Whitlock', age: 19, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Chen Yibing', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Anton Golotsutskov', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'He Kexin', age: 16, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Jonathan Horton', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Sandra Izbasa', age: 18, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Li Xiaopeng', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Kohei Uchimura', age: 19, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Xiao Qin', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Alexandra Eremia', age: 17, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Annia Hatch', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Terin Humphrey', age: 18, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Takehiro Kashima', age: 24, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Svetlana Khorkina', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Courtney Kupets', age: 18, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Anna Pavlova', age: 16, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Monica Rosu', age: 17, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Dana Sofronie', age: 16, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Hiroyuki Tomita', age: 23, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Marius Urzica', age: 28, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Isao Yoneda', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Yordan Yovchev', age: 31, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Oleksandr Beresh', age: 22, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Aleksey Bondarenko', age: 22, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Lee Ju-Hyeong', age: 27, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Li Xiaopeng', age: 19, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Liu Xuan', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Maria Olaru', age: 18, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yelena Produnova', age: 20, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Andreea Raducan', age: 16, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yang Wei', age: 20, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yordan Yovchev', age: 27, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Elisa Di Francisca', age: 29, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Arianna Errigo', age: 24, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Diego Occhiuzzi', age: 31, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Sun Yujie', age: 19, country: 'China', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Valentina Vezzali', age: 38, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Stefano Carozzo', age: 29, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Margherita Granbassi', age: 28, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Sada Jacobson', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Fabrice Jeannet', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Nicolas Lopez', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Matteo Tagliariol', age: 25, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Valentina Vezzali', age: 34, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Becca Ward', age: 18, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Mariel Zagunis', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Andrea Cassarà', age: 20, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Laura Flessel-Colovic', age: 32, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Aldo Montano', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Maureen Nisima', age: 23, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Salvatore Sanzo', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Mathieu Gourdain', age: 26, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Gianna Hablützel-Bürki', age: 30, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Rita König', age: 23, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Wiradech Kothny', age: 21, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Hugues Obry', age: 27, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Giovanna Trillini', age: 30, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Valentina Vezzali', age: 26, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Sandra Auffarth', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Laura Bechtolsheimer', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Adelinde Cornelissen', age: 33, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Charlotte Dujardin', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Michael Jung', age: 29, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Gerco Schröder', age: 34, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Tina Cook', age: 37, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Heike Kemmer', age: 46, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Eric Lamaze', age: 40, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Beezie Madden', age: 44, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Hinrich Romeike', age: 45, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Anky van Grunsven', age: 40, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Isabell Werth', age: 39, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Beatriz Ferrer-Salat', age: 38, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Pippa Funnell', age: 35, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Chris Kappler', age: 37, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Marco Kutscher', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Leslie Law', age: 39, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Ulla Salzgeber', age: 46, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kim Severson', age: 30, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Andrew Hoy', age: 41, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: "David O'Connor", age: 38, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Ulla Salzgeber', age: 42, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Anky van Grunsven', age: 32, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Isabell Werth', age: 31, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'David Boudia', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Chen Ruolin', age: 19, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'He Zi', age: 21, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Qin Kai', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Wu Minxia', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ilya Zakharov', age: 21, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Chen Ruolin', age: 15, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Gleb Galperin', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Guo Jingjing', age: 26, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Yuliya Pakhalina', age: 30, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Qin Kai', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Wang Xin', age: 16, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Wu Minxia', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Guo Jingjing', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Mathew Helm', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Lao Lishi', age: 16, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Chantelle Michell-Newbery', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Robert Newbery', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Yuliya Pakhalina', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Tian Liang', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Wu Minxia', age: 18, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Fu Mingxia', age: 22, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Guo Jingjing', age: 18, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Hu Jia', age: 17, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Li Na', age: 16, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Anne Montminy', age: 25, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Tian Liang', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Xiong Ni', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Grégory Baugé', age: 27, country: 'France', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Ed Clancy', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Sarah Hammer', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Chris Hoy', age: 36, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Jason Kenny', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Maximilian Levy', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Anna Meares', age: 28, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Vicki Pendleton', age: 31, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Laura Trott', age: 20, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Olga Zabelinskaya', age: 32, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Mickaël Bourgain', age: 28, country: 'France', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Fabian Cancellara', age: 27, country: 'Switzerland', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Jason Kenny', age: 20, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Joan Llaneras', age: 39, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Hayden Roulston', age: 27, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Bradley Wiggins', age: 28, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ryan Bayley', age: 22, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Graeme Brown', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Sergi Escobar', age: 29, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Rob Hayles', age: 31, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Brad McGee', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Anna Meares', age: 20, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Stefan Nimke', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Olga Slyusareva', age: 35, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Arnaud Tournant', age: 26, country: 'France', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'René Wolff', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Leontien Zijlaard-van Moorsel', age: 34, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Félicia Ballanger', age: 29, country: 'France', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Robert Bartko', age: 24, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Jens Fiedler', age: 30, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Jens Lehmann', age: 32, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Gary Neiwand', age: 34, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Jason Queally', age: 30, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Jan Ullrich', age: 26, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Lukáš Bauer', age: 32, country: 'Czech Republic', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Anna Haag', age: 23, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Marcus Hellner', age: 24, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Charlotte Kalla', age: 22, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Claudia Künzel-Nystad', age: 32, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Aino-Kaisa Saarinen', age: 31, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Evi Sachenbacher-Stehle', age: 29, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Axel Teichmann', age: 30, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Tobias Angerer', age: 28, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Yuliya Chepalova', age: 29, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yevgeny Dementyev', age: 23, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Giorgio Di Centa', age: 33, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Thobias Fredriksson', age: 30, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Claudia Künzel-Nystad', age: 28, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Björn Lind', age: 27, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Yevgeniya Medvedeva', age: 29, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Katerina Neumannová', age: 32, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Pietro Piller Cottrer', age: 31, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Kristina Šmigun-Vähi', age: 28, country: 'Estonia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Thomas Alsgaard', age: 30, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Viola Bauer', age: 25, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Anita Moen-Guidon', age: 34, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Katerina Neumannová', age: 28, country: 'Czech Republic', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Evi Sachenbacher-Stehle', age: 21, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kristen Skjeldal', age: 34, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Andrus Veerpalu', age: 31, country: 'Estonia', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Cristian Zorzi', age: 29, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Tina Dietze', age: 24, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Natasa Douchev-Janics', age: 30, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Katalin Kovács', age: 36, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Danuta Kozák', age: 25, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Inna Osypenko-Radomska', age: 29, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Franziska Weber', age: 23, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Tim Brabants', age: 31, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'David Cal', age: 25, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Natasa Douchev-Janics', age: 26, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Christian Gille', age: 32, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Katalin Kovács', age: 32, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Vadim Makhnyov', age: 28, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Roman Petrushenko', age: 27, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Katrin Wagner-Augustin', age: 30, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Ken Wallace', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Tomasz Wylenzek', age: 25, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Nathan Baggaley', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'David Cal', age: 21, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Andreas Dittmer', age: 32, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Natasa Douchev-Janics', age: 22, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Birgit Fischer-Schmidt', age: 42, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Aleksandr Kostoglod', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Katalin Kovács', age: 28, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Aleksandr Kovalyov', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Eirik Verås Larsen', age: 28, country: 'Norway', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Carolin Leonhardt', age: 19, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Adam Van Koeverden', age: 22, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Andreas Dittmer', age: 28, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Birgit Fischer-Schmidt', age: 38, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Knut Holmann', age: 32, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Zoltán Kammerer', age: 22, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Katalin Kovács', age: 24, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Petar Merkov', age: 23, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Florin Popescu', age: 26, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Mitica Pricop', age: 22, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Botond Storcz', age: 25, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Szilvia Szabó', age: 21, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Katrin Wagner-Augustin', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Kevin Kuske', age: 31, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'André Lange', age: 36, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Martin Annen', age: 32, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Beat Hefti', age: 28, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Kevin Kuske', age: 27, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'André Lange', age: 32, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ole Einar Bjørndalen', age: 36, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Marie Laure Brunet', age: 21, country: 'France', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Marie Dorin', age: 23, country: 'France', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Simone Hauswald', age: 30, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Vincent Jay', age: 24, country: 'France', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Anastasia Kuzmina', age: 25, country: 'Slovakia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Christoph Sumann', age: 34, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Yevgeny Ustyugov', age: 24, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Olga Zaytseva', age: 31, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Florence Baverel-Robert', age: 31, country: 'France', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Vincent Defrasne', age: 28, country: 'France', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Halvard Hanevold', age: 36, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Svetlana Ishmuratova', age: 33, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Anna-Carin Olofsson-Zidek', age: 32, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Uschi Disl', age: 31, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Sven Fischer', age: 30, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Ricco Groß', age: 31, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Andrea Henkel', age: 24, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Frank Luck', age: 34, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Raphaël Poirée', age: 27, country: 'France', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Olga Pylyova-Medvedtseva', age: 26, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Liv Grete Skjelbreid-Poirée', age: 27, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Magdalena Wallin-Forsberg', age: 34, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Zhao Yunlei', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Lee Hyo-Jeong', age: 27, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yu Yang', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Gao Ling', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Gao Ling', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Nataliya Antyukh', age: 31, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Veronica Campbell-Brown', age: 30, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Vivian Cheruiyot', age: 28, country: 'Kenya', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Will Claye', age: 21, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Tirunesh Dibaba', age: 27, country: 'Ethiopia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Mo Farah', age: 29, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Justin Gatlin', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Lalonde Gordon', age: 23, country: 'Trinidad and Tobago', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Sanya Richards-Ross', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'DeeDee Trotter', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Elvan Abeylegesse', age: 25, country: 'Turkey', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Kenenisa Bekele', age: 26, country: 'Ethiopia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Kerron Clement', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Tirunesh Dibaba', age: 23, country: 'Ethiopia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Walter Dix', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Allyson Felix', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yuliya Gushchina', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Tatyana Lebedeva', age: 32, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'LaShawn Merritt', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'David Neville', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Sanya Richards-Ross', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Kerron Stewart', age: 24, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Jared Tallent', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Angelo Taylor', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Richard Thompson', age: 23, country: 'Trinidad and Tobago', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Jeremy Wariner', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Shericka Williams', age: 22, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Nataliya Antyukh', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Kenenisa Bekele', age: 22, country: 'Ethiopia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Derrick Brew', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Shawn Crawford', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Hicham El Guerrouj', age: 29, country: 'Morocco', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Maurice Greene', age: 30, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Otis Harris', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kelly Holmes', age: 34, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Tatyana Lebedeva', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Jeremy Wariner', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ato Boldon', age: 26, country: 'Trinidad and Tobago', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Pauline Davis-Thompson', age: 34, country: 'Bahamas', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Lorraine Graham', age: 27, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Maurice Greene', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Greg Haughton', age: 26, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Deon Hemmings', age: 31, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Robert Korzeniowski', age: 32, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Tayna Lawrence', age: 25, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Beverly McDonald', age: 30, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Merlene Ottey-Page', age: 40, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Irina Privalova', age: 31, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Gabriela Szabo', age: 24, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Gete Wami', age: 25, country: 'Ethiopia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Elisabeth Görgl', age: 28, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Lindsey Kildow-Vonn', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Ivica Kostelic', age: 30, country: 'Croatia', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Julia Mancuso', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Tina Maze', age: 26, country: 'Slovenia', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Maria Riesch', age: 25, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Michaela Dorfmeister', age: 32, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Janica Kostelic', age: 24, country: 'Croatia', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Hermann Maier', age: 33, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Benjamin Raich', age: 27, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Marlies Schild', age: 24, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Rainer Schönfelder', age: 28, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Kjetil André Aamodt', age: 30, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Renate Götschl', age: 26, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Lasse Kjus', age: 31, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Bode Miller', age: 24, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Anja Pärson', age: 20, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Benjamin Raich', age: 23, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Ki Bo-Bae', age: 24, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Oh Jin-Hyek', age: 30, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Park Gyeong-Mo', age: 32, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Park Seong-Hyeon', age: 25, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yun Ok-Hui', age: 23, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Zhang Juanjuan', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Lee Seong-Jin', age: 19, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Park Seong-Hyeon', age: 21, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Kim Nam-Sun', age: 20, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kim Su-Nyeong', age: 29, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Vic Wunderle', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Yun Mi-Jin', age: 17, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Artur Aleksanyan', age: 20, country: 'Armenia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Valeriy Andriitsev', age: 25, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rövs?n Bayramov', age: 25, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jordan Burroughs', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Clarissa Chun', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yogeshwar Dutt', age: 29, country: 'India', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jaime Espinal', age: 27, country: 'Puerto Rico', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Johan Eurén', age: 27, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karam Gaber', age: 32, country: 'Egypt', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniyal Gadzhiyev', age: 26, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Komeil Ghasemi', age: 24, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giorgi Gogshelidze', age: 32, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sadegh Goudarzi', age: 24, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steeve Guénot', age: 26, country: 'France', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carol Huynh', age: 31, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kaori Icho', age: 28, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Damian Janikowski', age: 23, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jing Ruixue', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Arsen Julfalakyan', age: 25, country: 'Armenia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Riza Kayaalp', age: 22, country: 'Turkey', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandras Kazakevicius', age: 26, country: 'Lithuania', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vladimer Khinchegashvili', age: 21, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alan Khugayev', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Hyeon-Wu', age: 23, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Besik Kudukhov', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sushil Kumar', age: 29, country: 'India', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zaur Kuramagomedov', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ehsan Naser Lashgari', age: 26, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Revaz Lashkhi', age: 24, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jimmy Lidberg', age: 30, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Liván López', age: 30, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mijaín López', age: 29, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamás Lorincz', age: 25, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bilyal Makhov', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gyuzel Manyurova', age: 34, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dato Marsagishvili', age: 21, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ryutaro Matsumoto', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Péter Módos', age: 24, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Davit Modzmanashvili', age: 25, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heiki Nabi', age: 27, country: 'Estonia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Omid Noroozi', age: 26, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hitomi Obara', age: 31, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dzhamal Otarsultanov', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Xetaq Qazyumov', age: 29, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuliya Ratkeviç', age: 27, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jackeline Rentería', age: 26, country: 'Colombia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ghasem Rezaei', age: 26, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Coleman Scott', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mingiyan Semyonov', age: 22, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Soronzonboldyn Battsetseg', age: 22, country: 'Mongolia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hamid Soryan', age: 26, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariya Stadnik', age: 24, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'S?rif S?rifov', age: 23, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Akzhurek Tanatarov', age: 25, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Artur Taymazov', age: 33, country: 'Uzbekistan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Soslan Tigiyev', age: 28, country: 'Uzbekistan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rustam Totrov', age: 28, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Denis Tsargush', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Manuchar Tskhadaia', age: 27, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maider Unda', age: 35, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jake Varner', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tonya Verbeek', age: 34, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roman Vlasov', age: 21, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lyubov Volosova', age: 29, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Vorobyova', age: 21, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yang Kyong-Il', age: 23, country: 'North Korea', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatsuhiro Yonemitsu', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Saori Yoshida', age: 29, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shinichi Yumoto', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stanka Zlateva', age: 29, country: 'Bulgaria', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Emin ?hm?dov', age: 25, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Togrul ?sg?rov', age: 19, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yusuf Abdusalomov', age: 30, country: 'Tajikistan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bakhtiyar Akhmedov', age: 21, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Islam-Beka Albiyev', age: 19, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roman Amoyan', age: 24, country: 'Armenia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nazmi Avluca', age: 31, country: 'Turkey', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Khasan Baroyev', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mavlet Batyrov', age: 24, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rövs?n Bayramov', age: 21, country: 'Azerbaijan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kanat Begaliyev', age: 24, country: 'Kyrgyzstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Henry Cejudo', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chang Yongxiang', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Taras Danko', age: 28, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mirko Englich', age: 29, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vasyl Fedoryshyn', age: 27, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zoltán Fodor', age: 23, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Murad Gaydarov', age: 28, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giorgi Gogshelidze', age: 28, country: 'Georgia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christophe Guénot', age: 29, country: 'France', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Steeve Guénot', age: 22, country: 'France', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kyoko Hamaguchi', age: 30, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carol Huynh', age: 27, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chiharu Icho', age: 26, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kaori Icho', age: 24, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Manuchar K'virk'elia", age: 29, country: 'Georgia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alyona Kartashova', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Georgy Ketoyev', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aslanbek Khushtov', age: 28, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Besik Kudukhov', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sushil Kumar', age: 25, country: 'India', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mijaín López', age: 25, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aset Mambetov', age: 26, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nazyr Mankiyev', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tomohiro Matsunaga', age: 28, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iryna Merleni-Mykulchyn', age: 26, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Randi Miller', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Revaz Mindorashvili', age: 32, country: 'Georgia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrea Minguzzi', age: 26, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mindaugas Mizgaitis', age: 28, country: 'Lithuania', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Seyed Mohammadi', age: 28, country: 'Iran', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sharvani Muradov', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Musulbes', age: 36, country: 'Slovakia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marid Mutalimov', age: 28, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Park Eun-Chul', age: 27, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yury Patrikeyev', age: 28, country: 'Armenia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xetaq Qazyumov', age: 25, country: 'Azerbaijan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jackeline Rentería', age: 22, country: 'Colombia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vitaliy R?himov', age: 23, country: 'Azerbaijan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ramazan Sahin', age: 25, country: 'Turkey', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Buvaisa Saytiyev', age: 33, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mikhail Semyonov', age: 24, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Shalygina', age: 21, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andriy Stadnik', age: 26, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Stadnik', age: 20, country: 'Azerbaijan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Artur Taymazov', age: 29, country: 'Uzbekistan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nurbakyt Tengizbayev', age: 25, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kiril Terziev', age: 24, country: 'Bulgaria', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Soslan Tigiyev', age: 24, country: 'Uzbekistan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Taymuraz Tigiyev', age: 26, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Otar Tushishvili', age: 30, country: 'Georgia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ruslan Tyumenbayev', age: 22, country: 'Kyrgyzstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Armen Vardanian', age: 25, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Radoslav Velikov', age: 24, country: 'Bulgaria', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tonya Verbeek', age: 31, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Jiao', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adam Wheeler', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Agnieszka Wieszczek', age: 25, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xu Li', age: 18, country: 'China', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yavor Yanakiev', age: 23, country: 'Bulgaria', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Saori Yoshida', age: 25, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kenichi Yumoto', age: 23, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stanka Zlateva', age: 25, country: 'Bulgaria', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stephen Abas', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ara Abrahamian', age: 29, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Khasan Baroyev', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mavlet Batyrov', age: 20, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Dokturishivili', age: 24, country: 'Uzbekistan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Seref Eroglu', age: 28, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iván Fundora', age: 28, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karam Gaber', age: 24, country: 'Egypt', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rulon Gardner', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Khadzhimurat Gatsalov', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lise Golliot-Legrand', age: 27, country: 'France', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Gomis', age: 30, country: 'France', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kyoko Hamaguchi', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ali Reza Heidari', age: 28, country: 'Iran', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Magamed Ibragimov', age: 21, country: 'Uzbekistan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chiharu Icho', age: 22, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kaori Icho', age: 20, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kenji Inoue', age: 27, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeong Ji-Hyeon', age: 21, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jamill Kelly', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Atryom Kyuregyan', age: 27, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gennady Laliyev', age: 25, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'István Majoros', age: 30, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vyacheslav Makarenko', age: 28, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gaydar Mamedaliyev', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mkhitar Manukyan', age: 31, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gyuzel Manyurova', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sara McMann', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iryna Merleni-Mykulchyn', age: 22, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Patricia Miranda', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Mishin', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roberto Monzón', age: 26, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Masoud Moustafa Gokar', age: 26, country: 'Iran', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mun Ui-Je', age: 29, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Makhach Murtazaliyev', age: 20, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'F?rid M?nsurov', age: 22, country: 'Azerbaijan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Armen Nazaryan', age: 30, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ramaz Nozadze', age: 20, country: 'Georgia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mehmet Özal', age: 30, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aydin Polatçi', age: 27, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yandro Quintana', age: 24, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ali Reza Rezaei', age: 28, country: 'Iran', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Varteres Samurgashev', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cael Sanderson', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Buvaisa Saytiyev', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sazhid Sazhidov', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chikara Tanabe', age: 29, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Artur Taymazov', age: 25, country: 'Uzbekistan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elbrus Tedieiev', age: 29, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Georgy Tsurtsumia', age: 23, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tonya Verbeek', age: 27, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Xu', age: 18, country: 'China', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marko Yli-Hannuksela', age: 30, country: 'Finland', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Saori Yoshida', age: 21, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Namiq Abdullayev', age: 29, country: 'Azerbaijan', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Filiberto Azcuy', age: 27, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sándor István Bárdosi', age: 23, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Serafim Barzakov', age: 25, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Islam Bayramukov', age: 29, country: 'Kazakhstan', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adem Bereket', age: 27, country: 'Turkey', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Terry Brands', age: 32, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yevhen Buslovych', age: 28, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Ak'ak'i Chachua", age: 31, country: 'Georgia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ali Reza Dabir', age: 23, country: 'Iran', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Debelka', age: 24, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rulon Gardner', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Arsen Gitinov', age: 23, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Glushkov', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sammie Henson', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mogamed Ibragimov', age: 26, country: 'Macedonia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniel Igali', age: 26, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jang Jae-Seong', age: 25, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Eldar K'urt'anidze", age: 28, country: 'Georgia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kang Yong-Gyun', age: 26, country: 'North Korea', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Amiran Kardanov', age: 24, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Murat Kardanov', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Karelin', age: 33, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim In-Seop', age: 27, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Matt Lindland', age: 30, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mikael Ljungberg', age: 30, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Garrett Lowney', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Juan Luis Marén', age: 29, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lincoln McIlravy', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mun Ui-Je', age: 25, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sagid Murtazaliyev', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Musulbes', age: 28, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katsuhiko Nagata', age: 26, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Armen Nazaryan', age: 26, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lázaro Rivas', age: 25, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexis Rodríguez', age: 22, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yoel Romero', age: 23, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'David Saldadze', age: 22, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Varteres Samurgashev', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adam Saytiyev', age: 22, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sheng Zetian', age: 27, country: 'China', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sim Gwon-Ho', age: 27, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brandon Slay', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Artur Taymazov', age: 21, country: 'Uzbekistan', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Murad Umakhanov', age: 23, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Mukhran Vakht'angadze", age: 27, country: 'Georgia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hamza Yerlikaya', age: 24, country: 'Turkey', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marko Yli-Hannuksela', age: 26, country: 'Finland', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ruslan Albegov', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sajjad Anoushiravani', age: 28, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Apti Aukhadov', age: 19, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bartlomiej Bonk', age: 27, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iván Cambar', age: 28, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zulfiya Chinshanlo', age: 19, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anatolii Cîrîcu', age: 23, country: 'Moldova', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roxana Cocos', age: 23, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oscar Figueroa', age: 29, country: 'Colombia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christine Girard', age: 27, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hsu Shu-Ching', age: 21, country: 'Chinese Taipei', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ilya Ilyin', age: 24, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cristina Iovu', age: 19, country: 'Moldova', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eko Irawan', age: 23, country: 'Indonesia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Ivanov', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuliya Kalina', age: 23, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatyana Kashirina', age: 21, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hripsime Khurshudyan', age: 25, country: 'Armenia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Un-Guk', age: 23, country: 'North Korea', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irina Kulesha', age: 26, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Xueying', age: 22, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lin Qingfeng', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lu Haojie', age: 21, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lu Xiaojun', age: 28, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maiya Maneza', age: 26, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Razvan Martin', age: 20, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hiromi Miyake', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Navab Nasirshelal', age: 23, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Om Yun-Chol', age: 20, country: 'North Korea', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Svetlana Podobedova', age: 26, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rim Jong-Sim', age: 19, country: 'North Korea', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kianoush Rostami', age: 21, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ryang Chun-Hwa', age: 21, country: 'North Korea', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Behdad Salimi', age: 22, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marina Shkermankova', age: 22, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pimsiri Sirikaew', age: 22, country: 'Thailand', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oleksiy Torokhtiy', age: 26, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Triyatno', age: 24, country: 'Indonesia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Svetlana Tsarukayeva', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Mingjuan', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wu Jingbiao', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valentin Xristov', age: 18, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Zabolotnaya', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhou Lulu', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adrian Zielinski', age: 23, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Khadzhimurat Akkayev', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrey Aryamnov', age: 20, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cao Lei', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Wei-Ling', age: 26, country: 'Chinese Taipei', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chen Xiexia', age: 25, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Yanqing', age: 29, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeny Chigishev', age: 29, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vencelas Dabaya', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gevorg Davtyan', age: 25, country: 'Armenia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Davydova', age: 23, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mariya Grabovetskaya', age: 21, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hoàng Anh Tu?n', age: 23, country: 'Vietnam', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ilya Ilyin', age: 20, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eko Irawan', age: 19, country: 'Indonesia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jang Mi-Ran', age: 24, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Prapawadee Jaroenrattanatarakoon', age: 24, country: 'Thailand', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Klokov', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olha Korobka', age: 22, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Szymon Kolecki', age: 26, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dmitry Lapikov', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Hongli', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liao Hui', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Liu Chunhong', age: 25, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Long Qingquan', age: 17, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lu Ying-Chi', age: 23, country: 'Chinese Taipei', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lu Yong', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tigran G. Martirosyan', age: 20, country: 'Armenia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tigran V. Martirosyan', age: 25, country: 'Armenia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Nekrasova', age: 20, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anastasiya Novikova', age: 26, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'O Jong-Ae', age: 24, country: 'North Korea', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sibel Özkan', age: 20, country: 'Turkey', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pak Hyon-Suk', age: 23, country: 'North Korea', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Rybakov', age: 26, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sa Jae-Hyeok', age: 23, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diego Fernando Salazar', age: 27, country: 'Colombia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Viktors Šcerbatihs', age: 33, country: 'Latvia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marina Shainova', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oksana Slivenko', age: 21, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Matthias Steiner', age: 25, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Triyatno', age: 20, country: 'Indonesia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alla Vazhenina', age: 25, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nadezhda Yevstyukhina', age: 20, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yoon Jin-Hee', age: 22, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhang Xiangxiang', age: 25, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Khadzhimurat Akkayev', age: 19, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sedat Artuç', age: 28, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giorgi Asanidze', age: 28, country: 'Georgia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Batyushko', age: 22, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dmitry Berestov', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Yanqing', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Veliçko Çolakov', age: 22, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pyrros Dimas', age: 32, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Milen Dobrev', age: 24, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sergey Filimonov', age: 29, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jang Mi-Ran', age: 20, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wandee Kameaim', age: 26, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zarema Kasayeva', age: 17, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eszter Krutzler', age: 23, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Le Maosheng', age: 26, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Bae-Yeong', age: 24, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Li Zhuo', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liu Chunhong', age: 21, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mabel Mosquera', age: 35, country: 'Colombia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Halil Mutlu', age: 31, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Oleg Perepechonov', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikolay Peshalov', age: 34, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gleb Pisarevsky', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Udomporn Polsak', age: 22, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Valentina Popova', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ihor Razoronov', age: 34, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hossein Reza Zadeh', age: 26, country: 'Iran', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ri Song-Hui', age: 25, country: 'North Korea', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Israel José Rubio', age: 23, country: 'Venezuela', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Raema Lisa Rumbewas', age: 23, country: 'Indonesia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrey Rybakov', age: 22, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Taner Sagir', age: 19, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Viktors Šcerbatihs', age: 29, country: 'Latvia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shi Zhiyong', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nataliya Skakun', age: 23, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatyana Stukalova', age: 28, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tang Gonghong', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nurcan Taylan', age: 20, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pawina Thongsuk', age: 25, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eduard Tyukin', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aree Wiratthaworn', age: 24, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Agata Wróbel', age: 22, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wu Meijin', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nataliya Zabolotnaya', age: 19, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhang Guozheng', age: 29, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Giorgi Asanidze', age: 25, country: 'Georgia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Galabin Boevski', age: 25, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Chemerkin', age: 28, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chen Xiaomin', age: 23, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pyrros Dimas', age: 28, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ding Meiyuan', age: 20, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cheryl Haworth', age: 17, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marc Huster', age: 30, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sri Indriyani', age: 21, country: 'Indonesia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Soraya Jiménez', age: 23, country: 'Mexico', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Akakios Kakiasvili', age: 31, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ioanna Khatziioannou', age: 26, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Szymon Kolecki', age: 18, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kuo Yi-Hang', age: 25, country: 'Chinese Taipei', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Lavrenov', age: 28, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Feng-Ying', age: 25, country: 'Chinese Taipei', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lin Weining', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karnam Malleswari', age: 25, country: 'India', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Georgi Markov', age: 22, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Erzsébet Márkus-Peresztegi', age: 31, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Arsen Melikyan', age: 24, country: 'Armenia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Viktor Mitrou', age: 27, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Halil Mutlu', age: 27, country: 'Turkey', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tara Nott-Cunningham', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ruth Ogbeifo', age: 28, country: 'Nigeria', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gennady Oleshchuk', age: 24, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikolay Peshalov', age: 30, country: 'Croatia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Petrov', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Valentina Popova', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hossein Reza Zadeh', age: 22, country: 'Iran', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ri Song-Hui', age: 21, country: 'North Korea', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Raema Lisa Rumbewas', age: 19, country: 'Indonesia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Leonidas Sabanis', age: 28, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Asaad Said Saif', age: 21, country: 'Qatar', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Winarni Binti Slamet', age: 24, country: 'Indonesia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Khassaraporn Suta', age: 28, country: 'Thailand', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hossein Tavakoli', age: 22, country: 'Iran', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alan Tsagaev', age: 23, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'María Isabel Urrutia', age: 35, country: 'Colombia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ronny Weller', age: 31, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Agata Wróbel', age: 19, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wu Wenxiong', age: 19, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yang Xia', age: 22, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhan Xugang', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Xiangxiang', age: 17, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matteo Aicardi', age: 26, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Milan Aleksic', age: 26, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Betsey Armstrong', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marta Bach', age: 19, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Samir Barac', age: 38, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gemma Beadsworth', age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrea Blas', age: 20, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Miho Boškovic', age: 29, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Victoria Brown', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ivan Buljubašic', age: 24, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Damir Buric', age: 31, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andro Bušlje', age: 26, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kami Craig', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nikša Dobud', age: 26, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Annika Dries', age: 20, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Espar', age: 19, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laura Ester', age: 22, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maurizio Felugo', age: 31, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pietro Figlioli', age: 28, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Filip Filipovic', age: 25, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Deni Fiorentini', age: 28, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valentino Gallo', age: 27, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maica García', age: 21, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Massimo Giacoppo', age: 29, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alex Giorgetti', age: 24, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Niccolò Gitto', age: 25, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Živko Gocic', age: 29, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kate Gynther', age: 30, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Igor Hinic', age: 36, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maro Jokovic', age: 24, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bronwen Knox', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Holly Lincoln-Smith', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura López', age: 24, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dušan Mandic', age: 18, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Courtney Mathewson', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alicia McCormack', age: 29, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ona Meseguer', age: 24, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lorena Miranda', age: 21, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stefan Mitrovic', age: 24, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jane Moran', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Petar Muslim', age: 24, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Slobodan Nikic', age: 29, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paulo Obradovic', age: 26, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mati Ortíz', age: 21, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jenny Pareja', age: 28, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Giacomo Pastorino', age: 32, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Josip Pavic', age: 30, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pilar Peña', age: 26, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Amaurys Perez', age: 36, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heather Petri', age: 34, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Duško Pijetlovic', age: 27, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gojko Pijetlovic', age: 28, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Danijel Premuš', age: 31, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christian Presciutti', age: 29, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrija Prlainovic', age: 25, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Glencora Ralph', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikola Raden', age: 27, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mel Rippon', age: 31, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kelly Rulon', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksa Šaponjic', age: 20, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Melissa Seidemann', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sophie Smith', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Slobodan Soro', age: 33, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ash Southern', age: 19, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jessica Steffens', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maggie Steffens', age: 19, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sandro Sukno', age: 22, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roser Tarragó', age: 19, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stefano Tempesti', age: 33, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vanja Udovicic', age: 29, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Frano Vican', age: 36, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brenda Villa', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rowie Webster', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lauren Wenger', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elsie Windes', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicola Zagame', age: 22, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Betsey Armstrong', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tony Azevedo', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ryan Bailey', age: 32, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gemma Beadsworth', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Layne Beaubien', age: 32, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tibor Benedek', age: 36, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Péter Biros', age: 32, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brandon Brooks', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mieke Cabout', age: 22, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Patty Cardenas', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandar Ciric', age: 30, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kami Craig', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikita Cuffe', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniëlle de Bruijn', age: 30, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Filip Filipovic', age: 21, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Suzie Fraser', age: 19, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'István Gergely', age: 31, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Živko Gocic', age: 25, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Taniele Gofers', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Natalie Golda', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alison Gregorka', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rianne Guichelaar', age: 24, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kate Gynther', age: 26, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Biurakn Hakhverdian', age: 22, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brittany Hayes', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Amy Hetzel', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jaime Hipp', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Norbert Hosnyánszky', age: 24, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Hudnut', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tim Hutten', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tamás Kásás', age: 32, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gábor Kis', age: 25, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gergo Kiss', age: 30, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Noeki Klein', age: 25, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bronwen Knox', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emma Knox', age: 30, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simone Koot', age: 27, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'J. W. Krumpholz', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Norbert Madaras', age: 28, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alicia McCormack', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rick Merlo', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tamás Molnár', age: 33, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Merrill Moses', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Branko Pekovic', age: 29, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Heather Petri', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Duško Pijetlovic', age: 23, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeff Powers', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrija Prlainovic', age: 21, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikola Raden', age: 23, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bec Rippon', age: 29, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mel Rippon', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jenna Santoromito', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mia Santoromito', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandar Šapic', age: 30, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dejan Savic', age: 33, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Denis Šefik', age: 31, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alette Sijbring', age: 26, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yasemin Smit', age: 23, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jesse Smith', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Slobodan Soro', age: 29, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jessica Steffens', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zoltán Szécsi', age: 30, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vanja Udovicic', age: 25, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iefke van Belkum', age: 22, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gillian van den Berg', age: 36, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marieke van den Ham', age: 25, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ilse van der Meijden', age: 19, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Moriah Van Norman', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Peter Varellas', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dániel Varga', age: 24, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dénes Varga', age: 21, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamás Varga', age: 33, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brenda Villa', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vlada Vujasinovic', age: 34, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lauren Wenger', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elsie Windes', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adam Wright', age: 31, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carmela Allucci', age: 34, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alexandra Araujo', age: 32, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dimitra Asilian', age: 32, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roman Balashov', age: 27, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robin Beauregard', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tibor Benedek', age: 32, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Péter Biros', age: 28, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Silvia Bosurgi', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Revaz Chomakhidze', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandar Ciric', age: 26, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Francesca Conti', age: 32, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tania Di Mario', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Margaret Dingeldein', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Georgia Ellinaki', age: 30, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ellen Estes', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Fedorov', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rajmund Fodor', age: 28, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jacqueline Frank', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Garbuzov', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'István Gergely', age: 27, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elena Gigli', age: 19, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vladimir Gojkovic', age: 23, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Natalie Golda', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dmitry Gorshkov', age: 37, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Melania Grego', age: 31, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Danilo Ikodinovic', age: 27, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Viktor Jelenic', age: 33, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Predrag Jokic', age: 21, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eftykhia Karagianni', age: 30, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Angeliki Karapataki', age: 29, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tamás Kásás', age: 28, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gergo Kiss', age: 26, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nikolay Kozlov', age: 32, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Voula Kozomboli', age: 30, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Georgia Lara', age: 24, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kiki Liosi', age: 24, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ericka Lorenz', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Norbert Madaras', age: 24, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nikolay Maksimov', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giusi Malato', age: 33, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antiopi Melidoni', age: 26, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martina Miceli', age: 30, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamás Molnár', age: 29, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Heather Moody', age: 30, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tonia Moraiti', age: 27, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Evi Moraitidou', age: 29, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Thalia Munro', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maddalena Musumeci', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anthi Mylonaki', age: 20, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Slobodan Nikic', age: 21, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katerina Oikonomopoulou', age: 26, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heather Petri', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cinzia Ragusa', age: 27, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Rekechinsky', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Antigoni Roumbesi', age: 21, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kelly Rulon', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandar Šapic', age: 26, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dejan Savic', age: 29, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Denis Šefik', age: 27, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Amber Stachowski', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ádám Steinmetz', age: 24, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Barnabás Steinmetz', age: 28, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Stratan', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zoltán Szécsi', age: 26, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Noémi Tóth', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Petar Trbojevic', age: 30, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vanja Udovicic', age: 21, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tamás Varga', age: 29, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Attila Vári', age: 28, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brenda Villa', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vlada Vujasinovic', age: 31, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandr Yeryshov', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vitaly Yurchik', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marat Zakirov', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emanuela Zanchi', age: 26, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irek Zinnurov', age: 35, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marina Akobiya', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yekaterina Anikeyeva', age: 31, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roman Balashov', age: 23, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Robin Beauregard', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tibor Benedek', age: 28, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Péter Biros', age: 24, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Naomi Castle', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Revaz Chomakhidze', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandar Ciric', age: 22, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dmitry Dugin', age: 32, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ellen Estes', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rajmund Fodor', age: 24, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Joanne Fox', age: 21, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sergey Garbuzov', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dmitry Gorshkov', age: 33, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bridgette Gusterson', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Simone Hankin', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yvette Higgins', age: 22, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kate Hooper', age: 22, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Danilo Ikodinovic', age: 23, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Viktor Jelenic', age: 29, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Courtney Johnson', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tamás Kásás', age: 24, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gergo Kiss', age: 23, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sofiya Konukh', age: 20, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mariya Korolyova', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zoltán Kósz', age: 32, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nikolay Kozlov', age: 28, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikola Kuljaca', age: 26, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Kutuzova', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Svetlana Kuzina', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ericka Lorenz', age: 19, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikolay Maksimov', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tamás Märcz', age: 26, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bronwyn Mayer-Smith', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gail Miller', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Melissa Mills', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamás Molnár', age: 25, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Heather Moody', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Mo O'Toole", age: 39, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bernice Orwig', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicolle Payne', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heather Petri', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tatyana Petrova', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuliya Petrova', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Galina Rytova', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandar Šapic', age: 22, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dejan Savic', age: 25, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kathy Sheehy', age: 30, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Coralie Simmons', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Smurova', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandar Šoštar', age: 36, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Barnabás Steinmetz', age: 24, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Stratan', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julie Swail-Ertel', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zoltán Szécsi', age: 22, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bulcsú Székely', age: 24, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yelena Tokun', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Tolkunova', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Petar Trbojevic', age: 27, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Veljko Uskokovic', age: 29, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zsolt Varga', age: 28, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Attila Vári', age: 24, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yekaterina Vasilyeva', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jugoslav Vasovic', age: 26, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brenda Villa', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vlada Vujasinovic', age: 27, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nenad Vukanic', age: 26, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Debbie Watson', age: 34, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Liz Weekes', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Danielle Woodhouse', age: 31, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Taryn Woods', age: 25, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yury Yatsev', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandr Yeryshov', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marat Zakirov', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Predrag Zimonjic', age: 29, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irek Zinnurov', age: 31, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: '', age: 35, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: '', age: 29, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: '', age: 25, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Foluke Akinradewo', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Thiago Alves', age: 26, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikolay Apalikov', age: 29, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erika Araki', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrea Bari', age: 32, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yury Berezhko', age: 28, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lindsey Berg', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Emanuele Birarelli', age: 31, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dante Boninfante', age: 35, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Butko', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tandara Caixeta', age: 23, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adenízia da Silva', age: 25, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dante', age: 31, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicole Davis', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wallace de Souza', age: 25, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yukiko Ebata', age: 22, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fabi', age: 32, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fabiana', age: 27, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alessandro Fei', age: 33, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fernandinha', age: 32, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Giba', age: 35, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrea Giovi', age: 28, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Grankin', age: 27, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tayyiba Haneef-Park', age: 33, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christa Harmotto', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Megan Hodge', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Destinee Hooker', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dmitry Ilyinykh', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kaori Inoue', age: 29, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pereira de Carvalho Endres Jaque', age: 28, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maiko Kano', age: 24, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Taras Khtey', age: 30, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Saori Kimura', age: 25, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jordan Larson', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michal Lasko', age: 31, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dani Lins', age: 27, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luigi Mastrangelo', age: 36, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maksim Mikhaylov', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamari Miyashiro', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Murilo', age: 31, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dmitry Musersky', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hitomi Nakamichi', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leandro Neves', age: 29, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Obmochayev', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ai Otomo-Yamamoto', age: 30, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Samuele Papi', age: 39, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simone Parodi', age: 26, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paula', age: 30, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Natália Pereira', age: 23, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rodrigão', age: 33, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fernanda Rodrigues', age: 26, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lucas Saatkamp', age: 26, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Saori Sakoda', age: 24, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuko Sano', age: 33, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cristian Savani', age: 30, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Danielle Scott-Arruda', age: 39, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sheilla', age: 29, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Risa Shinnabe', age: 22, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sidão', age: 30, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandr Sokolov', age: 30, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yoshie Takeshita', age: 34, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Tetyukhin', age: 36, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thaísa', age: 25, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Courtney Thompson', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Logan Tom', age: 31, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dragan Travica', age: 25, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Volkov', age: 27, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mai Yamaguchi', age: 29, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ivan Zaytsev', age: 23, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robyn Ah Mow-Santos', age: 32, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anderson', age: 34, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lloy Ball', age: 36, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yury Berezhko', age: 24, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lindsey Berg', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heather Bown', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bruninho', age: 22, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carol', age: 31, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dante', age: 27, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicole Davis', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Escadinha', age: 32, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fabi', age: 28, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fabiana', age: 23, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Feng Kun', age: 29, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fofão', age: 38, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gabe Gardner', age: 32, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Giba', age: 31, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Glass', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Grankin', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gustavo', age: 32, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tayyiba Haneef-Park', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kevin Hansen', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'André Heller', age: 32, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tom Hoff', age: 35, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pereira de Carvalho Endres Jaque', age: 24, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jennifer Joines', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vadim Khamuttskikh', age: 38, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Korneyev', age: 27, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Kosaryev', age: 30, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Kuleshov', age: 29, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rich Lambourne', age: 33, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Lee', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Li Juan', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Liu Yanan', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ma Yunwen', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marcelinho', age: 33, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mari', age: 24, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maksim Mikhaylov', age: 20, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ryan Millar', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Murilo', age: 27, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'André Nascimento', age: 29, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ogonna Nnamani', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Ostapenko', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paula', age: 26, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Semyon Poltavsky', age: 27, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Reid Priddy', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rodrigão', age: 29, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sean Rooney', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Riley Salmon', age: 32, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Samuel', age: 24, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sassá', age: 25, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Danielle Scott-Arruda', age: 35, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sheilla', age: 25, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Clay Stanley', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stacy Sykora', age: 31, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Tetyukhin', age: 32, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thaísa', age: 21, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Logan Tom', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Scott Touzinsky', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Valeskinha', age: 32, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Verbov', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Volkov', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Walewska', age: 29, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wang Yimei', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wei Qiuyue', age: 19, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Willoughby', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Xu Yunli', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xue Ming', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yang Hao', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhang Na', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhao Ruirui', age: 26, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhou Suhong', age: 29, country: 'China', year: 2008, date: '24/08/2008', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pavel Abramov', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anderson', age: 30, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeniya Artamonova-Estes', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Baranov', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zoila Barros', age: 28, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Batukhtina-Tyurina', age: 33, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rosir Calderon', age: 19, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nancy Carrillo', age: 18, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matej Cernic', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chen Jing', age: 28, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olga Chukanova', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alberto Cisolla', age: 26, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paolo Cozzi', age: 24, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dante', age: 23, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stanislav Dineykin', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Escadinha', age: 28, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alessandro Fei', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Feng Kun', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ana Ivis Fernández', age: 31, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yekaterina Gamova', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrea Giani', age: 34, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Giba', age: 27, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Giovane', age: 33, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gustavo', age: 28, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'André Heller', age: 28, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Kazakov', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vadim Khamuttskikh', age: 34, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Taras Khtey', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Kosaryev', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Kuleshov', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Shan', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Liu Yanan', age: 23, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mayvelis Martínez', age: 27, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Luigi Mastrangelo', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maurício', age: 36, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Liana Mesa', age: 26, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anniara Muñoz', age: 24, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nalbert', age: 30, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'André Nascimento', age: 25, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olga Nikolayeva', age: 32, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yaima Ortíz', age: 22, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Samuele Papi', age: 31, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Damiano Pippi', age: 32, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Plotnikova', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daimí Ramírez', age: 20, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ricardinho', age: 28, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rodrigão', age: 25, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yumilka Ruíz', age: 26, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marta Sánchez', age: 31, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrea Sartoretti', age: 33, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marina Sheshenina', age: 19, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ventzislav Simeonov', age: 27, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lyubov Sokolova-Shashkova', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Song Nina', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irina Tebenikhina', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dulce Téllez', age: 20, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Tetyukhin', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelizaveta Tishchenko', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paolo Tofoli', age: 38, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Konstantin Ushakov', age: 34, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Verbov', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Valerio Vermiglio', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Lina', age: 26, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yang Hao', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Yegorchev', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhang Na', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Ping', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Yuehong', age: 28, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhao Ruirui', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhou Suhong', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tai Aguero', age: 23, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeniya Artamonova-Estes', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vladimir Batez', age: 31, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yelena Batukhtina-Tyurina', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anastasiya Belikova', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Regla Bell', age: 30, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Slobodan Boškan', age: 25, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marco Bracci', age: 34, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mirko Corsano', age: 26, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marlenis Costa', age: 27, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elisângela', age: 21, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alessandro Fei', age: 21, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ana Ivis Fernández', age: 27, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fofão', age: 30, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mirka Francis', age: 25, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yekaterina Gamova', age: 19, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrea Gardini', age: 34, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Gerasimov', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrija Geric', age: 23, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrea Giani', age: 30, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lena Godina', age: 22, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valery Goryushev', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tatyana Gracheva', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pasquale Gravina', age: 30, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikola Grbic', age: 27, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vladimir Grbic', age: 29, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Janina', age: 27, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karin', age: 28, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kátia', age: 27, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Kazakov', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kely', age: 25, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vadim Khamuttskikh', age: 30, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kiki', age: 20, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Slobodan Kovac', age: 33, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Kuleshov', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Leila', age: 28, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mireya Luis', age: 33, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luigi Mastrangelo', age: 25, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marco Meoni', age: 27, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ðula Mešter', age: 28, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vasa Mijic', age: 27, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ivan Miljkovic', age: 21, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeny Mitkov', age: 28, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nataliya Morozova', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ruslan Olikhver', age: 31, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Samuele Papi', age: 27, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olga Potashova', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Raquel', age: 22, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ricarda', age: 30, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simone Rosalba', age: 24, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yumilka Ruíz', age: 22, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Inessa Sargsyan', age: 28, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrea Sartoretti', age: 29, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ilya Savelyev', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Igor Shulepov', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lyubov Sokolova-Shashkova', age: 22, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Tetyukhin', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelizaveta Tishchenko', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paolo Tofoli', age: 34, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Regla Torres', age: 25, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Konstantin Ushakov', age: 30, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Vasilevskaya', age: 22, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Virna', age: 29, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Goran Vujevic', age: 27, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Igor Vušurovic', age: 25, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Walewska', age: 21, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roman Yakovlev', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Timo Boll', age: 31, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ai Fukuhara', age: 23, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Guo Yue', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sayaka Hirano', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kasumi Ishikawa', age: 19, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ju Se-Hyeok', age: 32, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Li Jia Wei', age: 30, country: 'Singapore', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ma Long', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'O Sang-Eun', age: 35, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bastian Steger', age: 31, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Jue Gu', age: 32, country: 'Singapore', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yu Seung-Min', age: 29, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Timo Boll', age: 27, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dang Ye-Seo', age: 27, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Feng Tian Wei', age: 21, country: 'Singapore', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Gyeong-A', age: 31, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Jia Wei', age: 27, country: 'Singapore', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'O Sang-Eun', age: 31, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dmitrij Ovtcharov', age: 19, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Park Mi-Yeong', age: 26, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christian Süß', age: 23, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Jue Gu', age: 28, country: 'Singapore', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yoon Jae-Young', age: 25, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yu Seung-Min', age: 26, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chen Qi', age: 20, country: 'China', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Guo Yue', age: 16, country: 'China', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Gyeong-A', age: 27, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Hyang-Mi', age: 24, country: 'North Korea', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ko Lai Chak', age: 28, country: 'Hong Kong', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Eun-Sil', age: 27, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Li Ching', age: 29, country: 'Hong Kong', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ma Lin', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michael Maze', age: 22, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Niu Jianfeng', age: 23, country: 'China', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Seog Eun-Mi', age: 27, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Finn Tugwell', age: 28, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Hao', age: 20, country: 'China', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Liqin', age: 26, country: 'China', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Nan', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yu Seung-Min', age: 22, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Jing', age: 31, country: 'Chinese Taipei', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Patrick Chila', age: 30, country: 'France', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jean-Philippe Gatien', age: 31, country: 'France', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Mu-Gyo', age: 25, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sun Jin', age: 20, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jan-Ove Waldner', age: 34, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Liqin', age: 22, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yan Sen', age: 25, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yang Ying', age: 23, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yu Ji-Hye', age: 24, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alistair Brownlee', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Triathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jonny Brownlee', age: 22, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Triathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Erin Densham', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Triathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Javier Gómez', age: 29, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Triathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lisa Nordén', age: 27, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Triathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicola Spirig', age: 30, country: 'Switzerland', year: 2012, date: '12/08/2012', sport: 'Triathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bevan Docherty', age: 31, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Triathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vanessa Fernandes', age: 22, country: 'Portugal', year: 2008, date: '24/08/2008', sport: 'Triathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jan Frodeno', age: 27, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Triathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emma Moffatt', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Triathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emma Snowsill', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Triathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Simon Whitfield', age: 33, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Triathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kate Allen', age: 34, country: 'Austria', year: 2004, date: '29/08/2004', sport: 'Triathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hamish Carter', age: 33, country: 'New Zealand', year: 2004, date: '29/08/2004', sport: 'Triathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bevan Docherty', age: 27, country: 'New Zealand', year: 2004, date: '29/08/2004', sport: 'Triathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Loretta Harrop', age: 29, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Triathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sven Riederer', age: 23, country: 'Switzerland', year: 2004, date: '29/08/2004', sport: 'Triathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Susan Williams', age: 35, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Triathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michellie Jones', age: 31, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Triathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brigitte McMahon', age: 33, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Triathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Magali Messmer', age: 29, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Triathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jan Rehula', age: 26, country: 'Czech Republic', year: 2000, date: '01/10/2000', sport: 'Triathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stephan Vuckovic', age: 28, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Triathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Simon Whitfield', age: 25, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Triathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dong Dong', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Trampoline', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'He Wenna', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Trampoline', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Huang Shanshan', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Trampoline', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lu Chunlong', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Trampoline', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rosie MacLennan', age: 23, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Trampoline', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Ushakov', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Trampoline', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jason Burnett', age: 21, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Trampoline', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Karen Cockburn', age: 28, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Trampoline', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dong Dong', age: 19, country: 'China', year: 2008, date: '24/08/2008', sport: 'Trampoline', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'He Wenna', age: 19, country: 'China', year: 2008, date: '24/08/2008', sport: 'Trampoline', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yekaterina Khilko', age: 26, country: 'Uzbekistan', year: 2008, date: '24/08/2008', sport: 'Trampoline', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lu Chunlong', age: 19, country: 'China', year: 2008, date: '24/08/2008', sport: 'Trampoline', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karen Cockburn', age: 24, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Trampoline', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anna Dogonadze-Lilkendey', age: 31, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Trampoline', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Huang Shanshan', age: 18, country: 'China', year: 2004, date: '29/08/2004', sport: 'Trampoline', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Moskalenko', age: 34, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Trampoline', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuriy Nikitin', age: 26, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Trampoline', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Henrik Stehlik', age: 23, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Trampoline', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karen Cockburn', age: 20, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Trampoline', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Karavayeva', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Trampoline', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Moskalenko', age: 30, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Trampoline', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Oksana Tsyhulova', age: 26, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Trampoline', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mathieu Turgeon', age: 21, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Trampoline', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ji Wallace', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Trampoline', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anastasiya Baryshnikova', age: 21, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sebastian Crismanich', age: 25, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Denisenko', age: 18, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robelis Despaigne', age: 24, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'María Espinoza', age: 24, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Helena Fromm', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nicolás García', age: 24, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joel González', age: 22, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anne-Caroline Graffe', age: 26, country: 'France', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marlene Harnois', age: 25, country: 'France', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hou Yuzhuo', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hwang Gyeong-Seon', age: 26, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Terrence Jennings', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jade Jones', age: 19, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lee Dae-Hun', age: 20, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liu Xiaobo', age: 28, country: 'China', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Milica Mandic', age: 20, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paige McPherson', age: 21, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carlo Molfetta', age: 28, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mohammad Bagheri Motamed', age: 26, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lutalo Muhammad', age: 21, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oscar Muñoz', age: 19, country: 'Colombia', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rohullah Nikpai', age: 25, country: 'Afghanistan', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anthony Obame', age: 23, country: 'Gabon', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mauro Sarmiento', age: 29, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chanatip Sonkham', age: 21, country: 'Thailand', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nur Tatar', age: 19, country: 'Turkey', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Servet Tazegül', age: 23, country: 'Turkey', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tseng Li-Cheng', age: 25, country: 'Chinese Taipei', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wu Jingyu', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brigitte Yagüe', age: 31, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lucija Zaninovic', age: 25, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Arman Chilmanov', age: 24, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chu Mu-Yen', age: 26, country: 'Chinese Taipei', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chika Chukwumerije', age: 24, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dalia Contreras', age: 24, country: 'Venezuela', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gwladys Epangue', age: 25, country: 'France', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'María Espinoza', age: 20, country: 'Mexico', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Natália Falavigna', age: 24, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hwang Gyeong-Seon', age: 22, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Im Su-Jeong', age: 22, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ja Dong-Min', age: 21, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diana Lopez', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mark Lopez', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steven Lopez', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yulis Mercedes', age: 28, country: 'Dominican Republic', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daynellis Montejo', age: 23, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alexandros Nikolaidis', age: 28, country: 'Greece', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rohullah Nikpai', age: 21, country: 'Afghanistan', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Guillermo Pérez', age: 28, country: 'Mexico', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Buttree Puedpong', age: 17, country: 'Thailand', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hadi Saei', age: 32, country: 'Iran', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sandra Šaric', age: 24, country: 'Croatia', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mauro Sarmiento', age: 25, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Karine Sergerie', age: 23, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nina Solheim', age: 29, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Son Tae-Jin', age: 20, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Stevenson', age: 25, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sung Yu-Chi', age: 26, country: 'Chinese Taipei', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Azize Tanrikulu', age: 22, country: 'Turkey', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Servet Tazegül', age: 19, country: 'Turkey', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wu Jingyu', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhu Guo', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martina Zubcic', age: 19, country: 'Croatia', year: 2008, date: '24/08/2008', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nia Abdallah', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Myriam Baverel', age: 23, country: 'France', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yaowapa Boorapolchai', age: 19, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adriana Carmona', age: 30, country: 'Venezuela', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chen Shih-Hsien', age: 25, country: 'Chinese Taipei', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Zhong', age: 21, country: 'China', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chu Mu-Yen', age: 22, country: 'Chinese Taipei', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pascal Gentil', age: 31, country: 'France', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Huang Chih-Hsiung', age: 27, country: 'Chinese Taipei', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hwang Gyeong-Seon', age: 18, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jang Ji-Won', age: 24, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Youssef Karami', age: 21, country: 'Iran', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yanely Labrada', age: 22, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steven Lopez', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luo Wei', age: 21, country: 'China', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mun Dae-Seong', age: 27, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elli Mystakidou', age: 27, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexandros Nikolaidis', age: 24, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hadi Saei', age: 28, country: 'Iran', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamer Salah', age: 22, country: 'Egypt', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iridia Salazar', age: 22, country: 'Mexico', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Óscar Salazar', age: 26, country: 'Mexico', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Song Myeong-Seop', age: 20, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bahri Tanrikulu', age: 24, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hamide Bikçin', age: 22, country: 'Turkey', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dominique Bosshart', age: 22, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lauren Burns', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Zhong', age: 17, country: 'China', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chi Shu-Ju', age: 17, country: 'Chinese Taipei', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Faissal Ebnoutalib', age: 29, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gabriel Esparza', age: 27, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Víctor Estrada', age: 28, country: 'Mexico', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pascal Gentil', age: 27, country: 'France', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Trude Gundersen', age: 23, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Huang Chih-Hsiung', age: 23, country: 'Chinese Taipei', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Ivanova', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jung Jae-Eun', age: 20, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Gyeong-Hun', age: 25, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lee Seon-Hui', age: 21, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Steven Lopez', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ángel Matos', age: 23, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Urbia Meléndez', age: 28, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mikhail Mouroutsos', age: 20, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yoriko Okamoto', age: 29, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hadi Saei', age: 24, country: 'Iran', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sin Jun-Sik', age: 20, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tr?n Hi?u Ngân', age: 26, country: 'Vietnam', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniel Trenton', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Taekwondo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julien Benneteau', age: 30, country: 'France', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bob Bryan', age: 34, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Juan Martín del Potro', age: 23, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roger Federer', age: 30, country: 'Switzerland', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Richard Gasquet', age: 26, country: 'France', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrea Hlavácková', age: 25, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lucie Hradecká', age: 27, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Kirilenko', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michaël Llodra', age: 32, country: 'France', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Max Mirnyi', age: 35, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nadiya Petrova', age: 30, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lisa Raymond', age: 38, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura Robson', age: 18, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Sharapova', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jo-Wilfried Tsonga', age: 27, country: 'France', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Venus Williams', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Simon Aspelin', age: 34, country: 'Sweden', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bob Bryan', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mike Bryan', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Dementyeva', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roger Federer', age: 27, country: 'Switzerland', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fernando González', age: 28, country: 'Chile', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Thomas Johansson', age: 33, country: 'Sweden', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anabel Medina', age: 26, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rafael Nadal', age: 22, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vivi Ruano', age: 34, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dinara Safina', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stanislas Wawrinka', age: 23, country: 'Switzerland', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Serena Williams', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Venus Williams', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yan Zi', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zheng Jie', age: 25, country: 'China', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vera Zvonaryova', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Novak Ðokovic', age: 21, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mario Ancic', age: 20, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mardy Fish', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Justine Henin-Hardenne', age: 22, country: 'Belgium', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicolas Kiefer', age: 27, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Li Ting', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ivan Ljubicic', age: 25, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Conchita Martínez', age: 32, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Amélie Mauresmo', age: 25, country: 'France', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alicia Molik', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vivi Ruano', age: 30, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rainer Schüttler', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paola Suárez', age: 28, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sun Tiantian', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Patricia Tarabini', age: 36, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kristie Boogert', age: 26, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Els Callens', age: 30, country: 'Belgium', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alex Corretja', age: 26, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Albert Costa', age: 25, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Dementyeva', age: 18, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Arnaud Di Pasquale', age: 21, country: 'France', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tommy Haas', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yevgeny Kafelnikov', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sébastien Lareau', age: 27, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniel Nestor', age: 28, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Miriam Oremans', age: 28, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Monica Seles', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dominique Van Roost', age: 27, country: 'Belgium', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Serena Williams', age: 18, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Todd Woodbridge', age: 29, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mark Woodforde', age: 34, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Clara Basiana', age: 21, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alba Cabello', age: 26, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chang Si', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chen Xiaojun', age: 20, country: 'China', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Margalida Crespi', age: 21, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anastasiya Davydova', age: 29, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariya Gromova', age: 28, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thais Henríquez', age: 29, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jiang Tingting', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jiang Wenwen', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elvira Khasyanova', age: 31, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paula Klamburg', age: 22, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Darya Korobova', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luo Xi', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Irene Montrucchio', age: 20, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandra Patskevich', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Laia Pons', age: 19, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alla Shishkina', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sun Wenyan', age: 22, country: 'China', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anzhelika Timanina', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wu Yiwen', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alba Cabello', age: 22, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Raquel Corral', age: 27, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Gromova', age: 24, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gu Beibei', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Saho Harada', age: 25, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thais Henríquez', age: 25, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Huang Xuechen', age: 18, country: 'China', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Ishchenko', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jiang Tingting', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jiang Wenwen', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Elvira Khasyanova', age: 27, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olga Kuzhela', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Liu Ou', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura López', age: 20, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luo Xi', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Ovchinnikova', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irina Rodríguez', age: 30, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Svetlana Romashina', age: 18, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Shorina', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sun Qiuting', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emiko Suzuki', age: 26, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paola Tirados', age: 28, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Na', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhang Xiaohuan', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Azarova', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olga Brusnikina', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tammy Crow', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Erin Dobratz', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michiyo Fujimaru', age: 25, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Gromova', age: 20, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Saho Harada', age: 21, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rebecca Jasontek', age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Naoko Kawashima', age: 23, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elvira Khasyanova', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariya Kiselyova', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kanako Kitao', age: 22, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sara Lowe', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lauren McFall', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stephanie Nesbitt', age: 19, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olga Novokshchenova', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Shorina', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emiko Suzuki', age: 22, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juri Tatsumi', age: 24, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yoko Yoneda', age: 28, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kendra Zanotto', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Antonova', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yelena Azarova', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lyne Beaumont', age: 22, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Claire Carver-Dias', age: 23, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Erin Chan', age: 21, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Virginie Dedieu', age: 21, country: 'France', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ayano Egami', age: 20, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Raika Fujii', age: 26, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Catherine Garceau', age: 22, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yoko Isoda', age: 22, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rei Jimbo', age: 26, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fanny Létourneau', age: 21, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Myriam Lignot', age: 25, country: 'France', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kirstin Normand', age: 26, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olga Novokshchenova', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yelena Soya', age: 18, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jacinthe Taillon', age: 23, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Reidun Tatham', age: 22, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Juri Tatsumi', age: 21, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuliya Vasilyeva', age: 22, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olga Vasyukova', age: 20, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yoko Yoneda', age: 24, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuko Yoneda', age: 21, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alyssa Anderson', age: 21, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Haley Anderson', age: 20, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Angie Bainbridge', age: 22, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Coralie Balmy', age: 25, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alain Bernard', age: 29, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Charlotte Bonnet', age: 17, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rachel Bootsma', age: 18, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cate Campbell', age: 20, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'César Cielo Filho', age: 25, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tyler Clary', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryan Cochrane', age: 23, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Natalie Coughlin', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'László Cseh Jr.', age: 26, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Tommaso D'Orsogna", age: 21, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dai Jun', age: 20, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Inge Dekker', age: 26, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Claire Donahue', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Conor Dwyer', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ophélie Etienne', age: 21, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Blair Evans', age: 21, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Margaux Farrell', age: 21, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jimmy Feigen', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Fesikov', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Takuro Fujii', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fabien Gilot', age: 28, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Grechin', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martina Grimaldi', age: 23, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dániel Gyurta', age: 23, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kosuke Hagino', age: 17, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hao Yun', age: 17, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brent Hayden', age: 28, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Femke Heemskerk', age: 24, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Natsumi Hoshi', age: 21, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Charlie Houchin', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dan Izotov', age: 20, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michael Jamieson', age: 23, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jiang Haiqi', age: 20, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jiao Liuyang', age: 22, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Leisel Jones', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuka Kato', age: 25, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kosuke Kitajima', age: 29, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yevgeny Korotyshkin', age: 29, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yolane Kukla', age: 16, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeny Lagunov', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Breeja Larson', age: 20, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mylene Lazare', age: 24, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Katie Ledecky', age: 15, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Libby Lenton-Trickett', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Caitlin Leverenz', age: 21, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jason Lezak', age: 36, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Li Xuanxu', age: 18, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Yunqi', age: 18, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikita Lobintsev', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lu Ying', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lu Zhiwu', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thomas Lurz', age: 32, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Grégory Mallet', age: 28, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Florent Manaudou', age: 21, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tyler McGill', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt McLean', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ruta Meilutyte', age: 15, country: 'Lithuania', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vladimir Morozov', age: 20, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lia Neal', age: 17, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jade Neilsen', age: 21, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kylie Palmer', age: 22, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lauren Perdue', age: 21, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thiago Pereira', age: 26, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brenton Rickard', age: 28, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Éva Risztov', age: 26, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hinkelien Schreuder', age: 28, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eric Shanteau', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hayden Stoeckel', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tang Yi', age: 19, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matt Targett', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Davis Tarwater', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryo Tateishi', age: 23, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Haruka Ueda', age: 24, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cameron van der Burgh', age: 24, country: 'South Africa', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Vanderkaay', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shannon Vreeland', age: 20, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Richard Weinberger', age: 22, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Amanda Weir', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuliya Yefimova', age: 20, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anastasiya Zuyeva', age: 22, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nathan Adrian', age: 19, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Angie Bainbridge', age: 18, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bronte Barratt', age: 19, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ricky Berens', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fréd Bousquet', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elaine Breeden', age: 19, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Grant Brits', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Caroline Burckle', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ashley Callus', age: 29, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Milorad Cavic', age: 24, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ryan Cochrane', age: 19, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ian Crocker', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lara Davenport', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dave Davies', age: 23, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Inge Dekker', age: 22, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ash Delaney', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nick Ffrost', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alessia Filippi', age: 21, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lotte Friis', age: 20, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Takuro Fujii', age: 23, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mark Gangloff', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fabien Gilot', age: 24, country: 'France', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brendan Hansen', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Femke Heemskerk', age: 20, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lara Ilchenko', age: 19, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sara Isakovic', age: 20, country: 'Slovenia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dan Izotov', age: 16, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jo Jackson', age: 21, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Larsen Jensen', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jiao Liuyang', age: 18, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cullen Jones', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mirna Jukic', age: 22, country: 'Austria', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Klete Keller', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ranomi Kromowidjojo', age: 17, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeny Lagunov', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liu Zige', age: 19, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nikita Lobintsev', age: 19, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Thomas Lurz', age: 28, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Linda MacKenzie', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Grégory Mallet', age: 24, country: 'France', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christine Marshall', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Takeshi Matsuda', age: 24, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oussama Mellouli', age: 24, country: 'Tunisia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alice Mills', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Junichi Miyashita', age: 24, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Reiko Nakamura', age: 26, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sara Nordenstam', age: 25, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lacey Nymeyer', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexander Dale Oen', age: 23, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kirk Palmer', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kylie Palmer', age: 18, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cassie Patten', age: 21, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Keri-Anne Payne', age: 20, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Federica Pellegrini', age: 20, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adam Pine', age: 32, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mikhail Polishchuk', age: 19, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Megan Quann-Jendrick', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hisayoshi Sato', age: 21, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Allison Schmitt', age: 18, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hinkelien Schreuder', age: 24, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emily Seebohm', age: 16, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emily Silver', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christian Sprenger', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Boris Steimetz', age: 21, country: 'France', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandr Sukhorukov', age: 20, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sun Ye', age: 19, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tan Miao', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tang Jingzhi', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maarten van der Weijden', age: 27, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Manon van Rooijen', age: 26, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Vandenberg', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marleen Veldhuis', age: 29, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erik Vendt', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dave Walters', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tarnee White', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ben Wildman-Tobriner', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Xu Tianlongzi', age: 17, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yang Yu', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhang Lin', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhao Jing', age: 17, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhou Yafei', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhu Qianwei', age: 17, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Georgina Bardach', age: 20, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'George Bovell', age: 21, country: 'Trinidad and Tobago', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emiliano Brembilla', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Federico Cappellazzo', age: 23, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simone Cercato', age: 29, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lars Conrad', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Haley Cope', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ritz Correia', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'László Cseh Jr.', age: 18, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Petra Dallmann', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dave Davies', age: 19, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Inge Dekker', age: 18, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Duje Draganja', age: 21, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steffen Driesen', age: 22, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hugues Duboscq', age: 22, country: 'France', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nate Dusing', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lyndon Ferns', age: 20, country: 'South Africa', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Solenne Figuès', age: 25, country: 'France', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Razvan Florea', age: 23, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mark Gangloff', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Scott Goldblatt', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniela Götz', age: 16, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Janina-Kristin Götz', age: 23, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chantal Groot', age: 21, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dániel Gyurta', age: 15, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sara Harstick', age: 22, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rhi Jeffrey', age: 17, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Larsen Jensen', age: 18, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Johan Kenkhuis', age: 24, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dan Ketchum', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tara Kirk', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Klim', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stanislava Komarova', age: 18, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Annabel Kosten', age: 27, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lenny Krayzelburg', age: 28, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jens Kruppa', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Colleen Lanne', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Li Ji', age: 18, country: 'China', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luo Xuejuan', age: 20, country: 'China', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Filippo Magnini', age: 22, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Antony Matkovich', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Helge Meeuw', age: 19, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Malia Metella', age: 22, country: 'France', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Diana Munz', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Reiko Nakamura', age: 22, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuko Nakanishi', age: 23, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ryk Neethling', age: 26, country: 'South Africa', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yoshihiro Okumura', age: 21, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pang Jiaying', age: 19, country: 'China', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steve Parry', age: 27, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Todd Pearson', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Federica Pellegrini', age: 16, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Matteo Pelliciari', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carly Piper', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Poewe', age: 21, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anne Poleska', age: 24, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Camelia Potec', age: 22, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Giaan Rooney', age: 21, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Massimiliano Rosolino', age: 26, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thomas Rupprath', age: 27, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sarah Ryan', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jess Schipper', age: 17, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andriy Serdinov', age: 21, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ai Shibata', age: 22, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicholas Sprenger', age: 19, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Craig Stevens', age: 24, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hannah Stockbauer', age: 22, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Darian Townsend', age: 19, country: 'South Africa', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Vanderkaay', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Veens', age: 26, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marleen Veldhuis', age: 25, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Erik Vendt', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dana Vollmer', age: 16, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gabe Woodward', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xu Yanwei', age: 20, country: 'China', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yang Yu', age: 19, country: 'China', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mitja Zastrow', age: 27, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhu Yingwen', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Klaas-Erik Zwering', age: 23, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sam Arsenault', age: 18, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Amanda Beard', age: 18, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'B. J. Bedford', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lindsay Benko', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Black', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gustavo Borges', age: 27, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Antje Buschschulte', age: 21, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ashley Callus', age: 21, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dyana Calub', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chad Carvin', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ian Crocker', age: 18, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nate Dusing', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Meike Freitag', age: 21, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lars Frölander', age: 26, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Fydler', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Scott Goldblatt', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elka Graham', age: 18, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chantal Groot', age: 17, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tommy Hannan', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Regan Harrison', age: 22, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sara Harstick', age: 19, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thamar Henneken', age: 21, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Penny Heyns', age: 25, country: 'South Africa', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Misty Hyman', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carlos Jayme', age: 20, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Louise Jöhncke', age: 24, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna-Karin Kammerling', age: 19, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Johan Kenkhuis', age: 20, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kerstin Kielgaß', age: 30, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bill Kirby', age: 25, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ágnes Kovács', age: 19, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristy Kowal', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniel Kowalski', age: 25, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jens Kruppa', age: 24, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Josefin Lillhage', age: 20, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tom Malchow', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roxana Maracineanu', age: 25, country: 'France', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sumika Minamoto', age: 21, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ryan Mitchell', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Curtis Myden', age: 26, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Miki Nakao', age: 22, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Justin Norris', age: 20, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Junko Onishi', age: 25, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Terence Parkin', age: 20, country: 'South Africa', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aaron Peirsol', age: 17, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kieren Perkins', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Erin Phenix', age: 19, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Popov', age: 28, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jamie Rauch', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Davide Rummolo', age: 22, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thomas Rupprath', age: 23, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sarah Ryan', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kaitlin Sandeno', age: 17, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xuxa Scherer', age: 25, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Edvaldo Silva Filho', age: 22, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Johanna Sjöberg', age: 22, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roman Sludnov', age: 20, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Torsten Spanneberg', age: 25, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Britta Steffen', age: 16, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Staciana Stitts', age: 19, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Julia Stowers', age: 18, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Malin Svahnström', age: 20, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Denys Sylantiev', age: 23, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yasuko Tajima', age: 19, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Masami Tanaka', age: 21, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cristina Teuscher', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chris Thompson', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kirsten Thomson', age: 16, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Scott Tucker', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Franziska van Almsick', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mark van der Zijden', age: 26, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jacinta Van Lint', age: 22, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wilma van Rijn-van Hofwegen', age: 29, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Manon van Rooijen', age: 18, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Erik Vendt', age: 19, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Josh Watson', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tarnee White', age: 19, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tom Wilkens', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marcel Wouda', age: 28, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nina Zhivanevskaya', age: 23, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martijn Zuijdweg', age: 23, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Guillaume Bastille', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Allison Baver', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simon Cho', age: 18, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kimberly Derrick', age: 24, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aly Dudek', age: 19, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Arianna Fontana', age: 19, country: 'Italy', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lana Gehring', age: 19, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jessica Gregg', age: 21, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gwak Yun-Gi', age: 20, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'François Hamelin', age: 23, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Travis Jayner', age: 27, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olivier Jean', age: 25, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Seong-Il', age: 19, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Eun-Byeol', age: 18, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jordan Malone', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kalyna Roberge', age: 23, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sun Linlin', age: 21, country: 'China', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tania Vicent', age: 34, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhang Hui', age: 21, country: 'China', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Éric Bédard', age: 29, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Byeon Cheon-Sa', age: 18, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marta Capurso', age: 25, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Arianna Fontana', age: 15, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gang Yun-Mi', age: 18, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jonathan Guilmette', age: 27, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Charles Hamelin', age: 21, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alex Izykowski', age: 22, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeon Da-Hye', age: 22, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'J. P. Kepka', age: 21, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alanna Kraus', age: 28, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Li Jiajun', age: 30, country: 'China', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'O Se-Jong', age: 23, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Amanda Overland', age: 24, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Evgeniya Radanova', age: 28, country: 'Bulgaria', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kalyna Roberge', age: 19, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Seo Ho-Jin', age: 22, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rusty Smith', age: 26, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Song Seog-U', age: 22, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mathieu Turcotte', age: 29, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tania Vicent', age: 30, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yang Yang (A)', age: 29, country: 'China', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Katia Zini', age: 24, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mara Zini', age: 26, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'An Yulong', age: 23, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michele Antonioli', age: 25, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Éric Bédard', age: 25, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Steven Bradbury', age: 28, country: 'Australia', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maurizio Carnino', age: 26, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fabio Carta', age: 24, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Isabelle Charest', age: 31, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Choi Min-Kyung', age: 19, country: 'South Korea', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marie-Eve Drolet', age: 20, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Feng Kai', age: 23, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nicola Franceschina', age: 24, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Amélie Goulet-Nadon', age: 19, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Guo Wei', age: 18, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ju Min-Jin', age: 18, country: 'South Korea', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alanna Kraus', age: 24, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Ye', age: 18, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Park Hye-Won', age: 18, country: 'South Korea', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicola Rodigari', age: 20, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rusty Smith', age: 22, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sun Dandan', age: 23, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'François-Louis Tremblay', age: 21, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tania Vicent', age: 26, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniela Anschütz-Thoms', age: 35, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jan Blokhuijsen', age: 20, country: 'Netherlands', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Håvard Bøkko', age: 23, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bob de Jong', age: 33, country: 'Netherlands', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anni Friesinger-Postma', age: 33, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Annette Gerritsen', age: 24, country: 'Netherlands', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mathieu Giroux', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brian Hansen', age: 19, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Masako Hozumi', age: 23, country: 'Japan', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Clara Hughes', age: 37, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joji Kato', age: 25, country: 'Japan', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nao Kodaira', age: 23, country: 'Japan', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jonathan Kuck', age: 19, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Simon Kuipers', age: 27, country: 'Netherlands', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lee Sang-Hwa', age: 20, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lucas Makowsky', age: 22, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Trevor Marsicano', age: 20, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katrin Mattscherodt', age: 28, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Denny Morrison', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Keiichiro Nagashima', age: 27, country: 'Japan', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christine Nesbitt', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maki Tabata', age: 35, country: 'Japan', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laurine van Riessen', age: 22, country: 'Netherlands', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Beixing', age: 24, country: 'China', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Katarzyna Wójcicka-Bachleda-Curus', age: 30, country: 'Poland', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jenny Wolf', age: 31, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katarzyna Wozniak', age: 20, country: 'Poland', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ireen Wüst', age: 23, country: 'Netherlands', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luiza Zlotkowska', age: 23, country: 'Poland', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yekaterina Abramova', age: 23, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matteo Anesi', age: 21, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniela Anschütz-Thoms', age: 31, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Varvara Barysheva', age: 28, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Svetlana Boyarkina-Zhurova', age: 34, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Arne Dankers', age: 25, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bob de Jong', age: 29, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stefano Donagrandi', age: 29, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Dorofeyev', age: 29, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steven Elm', age: 30, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Renate Groenewold', age: 29, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Gang-Seok', age: 20, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Galina Likhachova', age: 28, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yekaterina Lobysheva', age: 20, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Denny Morrison', age: 20, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christine Nesbitt', age: 20, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lucille Opitz', age: 28, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jason Parker', age: 30, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shannon Rempel', age: 21, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ren Hui', age: 22, country: 'China', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rintje Ritsma', age: 35, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ippolito Sanfratello', age: 32, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marianne Timmer', age: 31, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Tuitert', age: 25, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sabine Völker', age: 32, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Svetlana Vysokova', age: 33, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Manli', age: 32, country: 'China', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Justin Warsylewicz', age: 20, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jens Boden', age: 23, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jan Bos', age: 26, country: 'Netherlands', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kip Carpenter', age: 22, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joey Cheek', age: 22, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Casey FitzRandolph', age: 27, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anni Friesinger-Postma', age: 25, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Monique Garbrecht-Enfeldt', age: 33, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Renate Groenewold', age: 25, country: 'Netherlands', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Clara Hughes', age: 29, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cindy Klassen', age: 22, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Catriona Le May Doan', age: 31, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gianni Romme', age: 29, country: 'Netherlands', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hiroyasu Shimizu', age: 27, country: 'Japan', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gretha Smit', age: 26, country: 'Netherlands', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lasse Sætre', age: 27, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ådne Søndrål', age: 30, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gerard van Velde', age: 30, country: 'Netherlands', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Witty', age: 26, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Monica Abbott', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sandy Allen-Lewis', age: 29, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura Berg', age: 33, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jodie Bowering', age: 26, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Crystl Bustos', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kylie Cronk', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrea Duran', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Naho Emoto', age: 22, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jennie Finch', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tairia Flowers', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Motoko Fujimoto', age: 27, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vicky Galindo', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kelly Hardie', age: 38, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tanya Harding', age: 36, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Megu Hirose', age: 27, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emi Inui', age: 24, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sachiko Ito', age: 32, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lovie Jung', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ayumi Karino', age: 23, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kelly Kretschman', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lauren Lappin', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Caitlin Lowe', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Satoko Mabuchi', age: 26, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jessica Mendoza', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yukiyo Mine', age: 20, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Masumi Mishina', age: 26, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Simmone Morrow', age: 31, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tracey Mosley', age: 34, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rei Nishiyama', age: 24, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stacey Nuveman', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cat Osterman', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stacey Porter', age: 26, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Melanie Roche', age: 37, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hiroko Sakai', age: 29, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rie Sato', age: 27, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Justine Smethurst', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mika Someya', age: 25, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Danielle Stewart', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Natalie Titcume', age: 32, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yukiko Ueno', age: 26, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Natalie Ward', age: 32, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Natasha Watley', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Belinda Wright', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kerry Wyborn', age: 30, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eri Yamada', age: 24, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sandy Allen-Lewis', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laura Berg', age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Crystl Bustos', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marissa Carpadios', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Amanda Doman', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Peta Edebone', age: 35, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lisa Fernandez', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jennie Finch', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tairia Flowers', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Amanda Freed', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fiona Hanes-Crawford', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tanya Harding', age: 32, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lori Harrigan', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Natalie Hodgskin', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kazue Ito', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yumi Iwabuchi', age: 24, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lovie Jung', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kelly Kretschman', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jessica Mendoza', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Masumi Mishina', age: 22, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simmone Morrow', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tracey Mosley', age: 30, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Emi Naito', age: 24, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stacey Nuveman', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Leah O'Brien-Amico", age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cat Osterman', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stacey Porter', age: 22, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Melanie Roche', age: 33, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Haruka Saito', age: 34, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hiroko Sakai', age: 25, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Naoko Sakamoto', age: 19, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rie Sato', age: 24, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuki Sato', age: 23, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Juri Takayama', age: 27, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Natalie Titcume', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jenny Topping', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yukiko Ueno', age: 22, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Reika Utsugi', age: 41, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Natalie Ward', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Natasha Watley', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brooke Wilkins', age: 30, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kerry Wyborn', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eri Yamada', age: 20, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Noriko Yamaji', age: 33, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sandy Allen-Lewis', age: 21, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christie Ambrosi', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Misako Ando', age: 29, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laura Berg', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jo Brown', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jennifer Brundage', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Crystl Bustos', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sheila Cornell-Douty', age: 38, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kerry Dienelt', age: 31, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peta Edebone', age: 31, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sue Fairhurst', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lisa Fernandez', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Selina Follas', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yumiko Fujii', age: 28, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fiona Hanes-Crawford', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kelly Hardie', age: 30, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tanya Harding', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lori Harrigan', age: 30, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Danielle Henderson', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Taeko Ishikawa', age: 24, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kazue Ito', age: 22, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yoshimi Kobayashi', age: 32, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shiori Koseki', age: 28, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariko Masubuchi', age: 20, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Naomi Matsumoto', age: 32, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sally McDermid-McCreedy', age: 35, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jennifer McFalls', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Simmone Morrow', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emi Naito', age: 20, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stacey Nuveman', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Leah O'Brien-Amico", age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dot Richardson', age: 38, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Melanie Roche', age: 29, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Haruka Saito', age: 30, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michele Smith', age: 33, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Juri Takayama', age: 23, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hiroko Tamoto', age: 26, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Natalie Titcume', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Reika Utsugi', age: 37, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michelle Venturella', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Natalie Ward', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brooke Wilkins', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christa Williams', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Miyo Yamada', age: 24, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Noriko Yamaji', age: 30, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Softball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jasey-Jay Anderson', age: 34, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Déborah Anthonioz', age: 31, country: 'France', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mathieu Bozzetto', age: 36, country: 'France', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Torah Bright', age: 23, country: 'Australia', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kelly Clark', age: 26, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yekaterina Ilyukhina', age: 22, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Benjamin Karl', age: 24, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marion Kreiner', age: 28, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Scotty Lago', age: 22, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olivia Nobs', age: 27, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peetu Piiroinen', age: 22, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tony Ramoin', age: 21, country: 'France', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maëlle Ricker', age: 31, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mike Robertson', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicolien Sauerbreij', age: 30, country: 'Netherlands', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hannah Teter', age: 23, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Seth Wescott', age: 33, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shaun White', age: 23, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gretchen Bleiler', age: 24, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kjersti Buaas', age: 24, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paul-Henri De Le Rue', age: 21, country: 'France', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rosey Fletcher', age: 30, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tanja Frieden', age: 30, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sigi Grabner', age: 31, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lindsey Jacobellis', age: 20, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Danny Kass', age: 23, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Amelie Kober', age: 18, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Markku Koski', age: 24, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dominique Maltais', age: 25, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniela Meuli', age: 24, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Philipp Schoch', age: 26, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Simon Schoch', age: 27, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hannah Teter', age: 19, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Seth Wescott', age: 29, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shaun White', age: 19, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Radoslav Židek', age: 24, country: 'Slovakia', year: 2006, date: '26/02/2006', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Isabelle Blanc', age: 26, country: 'France', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kelly Clark', age: 18, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Danny Kass', age: 19, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chris Klug', age: 29, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ross Powers', age: 23, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fabienne Reuteler', age: 22, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Richard Richardsson', age: 28, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Karine Ruby', age: 24, country: 'France', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Philipp Schoch', age: 22, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'JJ Thomas', age: 20, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lidia Trettel', age: 28, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Doriane Vidal', age: 25, country: 'France', year: 2002, date: '24/02/2002', sport: 'Snowboarding', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anders Bardal', age: 27, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Johan Remen Evensen', age: 24, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tom Hilde', age: 22, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anders Jacobsen', age: 25, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreas Kofler', age: 25, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wolfgang Loitzl', age: 30, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thomas Morgenstern', age: 23, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michael Neumayer', age: 31, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martin Schmitt', age: 32, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Uhrmann', age: 31, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andreas Wank', age: 22, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Janne Ahonen', age: 28, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Janne Happonen', age: 21, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tommy Ingebrigtsen', age: 28, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tami Kiuru', age: 29, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martin Koch', age: 24, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bjørn Einar Romøren', age: 24, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreas Widhölzl', age: 29, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Janne Ahonen', age: 24, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Damjan Fras', age: 28, country: 'Slovenia', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stephan Hocke', age: 18, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Risto Jussilainen', age: 26, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Robert Kranjec', age: 20, country: 'Slovenia', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Veli-Matti Lindström', age: 18, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Primož Peterka', age: 22, country: 'Slovenia', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martin Schmitt', age: 24, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michael Uhrmann', age: 23, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Žonta', age: 23, country: 'Slovenia', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martins Dukurs', age: 25, country: 'Latvia', year: 2010, date: '28/02/2010', sport: 'Skeleton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anja Huber', age: 26, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Skeleton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jon Montgomery', age: 30, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Skeleton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kerstin Szymkowiak', age: 32, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Skeleton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandr Tretyakov', age: 24, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Skeleton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Amy Williams', age: 27, country: 'Great Britain', year: 2010, date: '28/02/2010', sport: 'Skeleton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Duff Gibson', age: 39, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Skeleton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mellisa Hollingsworth-Richards', age: 25, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Skeleton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeff Pain', age: 35, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Skeleton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maya Pedersen', age: 33, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Skeleton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shelley Rudman', age: 24, country: 'Great Britain', year: 2006, date: '26/02/2006', sport: 'Skeleton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gregor Stähli', age: 37, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Skeleton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alex Coomber', age: 28, country: 'Great Britain', year: 2002, date: '24/02/2002', sport: 'Skeleton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tristan Gale', age: 21, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Skeleton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lea Ann Parsley', age: 33, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Skeleton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martin Rettl', age: 28, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Skeleton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jim Shea Jr.', age: 33, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Skeleton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gregor Stähli', age: 33, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Skeleton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nasser Al-Attiya', age: 41, country: 'Qatar', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fehaid Al-Deehani', age: 45, country: 'Kuwait', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Danka Barteková', age: 27, country: 'Slovakia', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jamie Beyerle-Gray', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sylwia Bogacka', age: 30, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Giovanni Cernogoraz', age: 29, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Ying', age: 34, country: 'China', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Choi Yeong-Rae', age: 30, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lionel Cox', age: 31, country: 'Belgium', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Håkan Dahlby', age: 46, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rajmond Debevec', age: 49, country: 'Slovenia', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ding Feng', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matt Emmons', age: 31, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Massimo Fabbrizi', age: 34, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Celine Goberville', age: 25, country: 'France', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anders Golding', age: 28, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Guo Wenjun', age: 28, country: 'China', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vincent Hancock', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Jang-Mi', age: 19, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Jong-Hyeon', age: 27, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vijay Kumar', age: 26, country: 'India', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ivana Maksimovic', age: 22, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Martynov', age: 44, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alin Moldoveanu', age: 29, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vasily Mosin', age: 40, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gagan Narang', age: 29, country: 'India', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leuris Pupo', age: 35, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Delphine Racinet-Reau', age: 38, country: 'France', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Rhode', age: 33, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jessica Rossi', age: 20, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zuzana Štefeceková', age: 28, country: 'Slovakia', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adéla Sýkorová', age: 25, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Luca Tesconi', age: 30, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Zhiwei', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wei Ning', age: 29, country: 'China', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Peter Wilson', age: 25, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yi Siling', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yu Dan', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrija Zlatic', age: 34, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Artur Aivazian', age: 35, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Alipov', age: 33, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Abhinav Bindra', age: 25, country: 'India', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christine Brinker-Wenzel', age: 27, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tore Brovold', age: 38, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chiara Cainero', age: 30, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Ying', age: 30, country: 'China', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Corey Cogdell', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eglis Yaima Cruz', age: 28, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Francesco D'Aniello", age: 39, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rajmond Debevec', age: 45, country: 'Slovenia', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Munkhbayar Dorjsuren', age: 39, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Du Li', age: 26, country: 'China', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Glenn Eller', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt Emmons', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lyubov Galkina', age: 35, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Guo Wenjun', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Henri Häkkinen', age: 28, country: 'Finland', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vincent Hancock', age: 19, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hu Binyuan', age: 30, country: 'China', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vladimir Isakov', age: 38, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Kostelecký', age: 33, country: 'Czech Republic', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Satu Mäkelä-Nummela', age: 37, country: 'Finland', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Otryadyn Gündegmaa', age: 30, country: 'Mongolia', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nataliya Paderina', age: 32, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pang Wei', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Snježana Pejcic', age: 26, country: 'Croatia', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giovanni Pellielo', age: 38, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oleksandr Petriv', age: 34, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Warren Potent', age: 46, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Qiu Jian', age: 33, country: 'China', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christian Reitz', age: 21, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Rhode', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nino Salukvadze', age: 39, country: 'Georgia', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ralf Schumann', age: 46, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zuzana Štefeceková', age: 24, country: 'Slovakia', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuriy Sukhorukov', age: 40, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tan Zongliang', age: 36, country: 'China', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anthony Terras', age: 23, country: 'France', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jason Turner', age: 33, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhu Qinan', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ahmed Al-Maktoum', age: 40, country: 'United Arab Emirates', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sergey Alifirenko', age: 45, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Alipov', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michael Anti', age: 40, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Irad? Asumova', age: 46, country: 'Azerbaijan', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Suzy Balogh', age: 31, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrea Benelli', age: 44, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Blinov', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Du Li', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt Emmons', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gao E', age: 41, country: 'China', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jozef Gönci', age: 30, country: 'Slovakia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lenka Hyková-Marušková', age: 19, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Diána Igaly', age: 39, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vladimir Isakov', age: 34, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jia Zhanbo', age: 30, country: 'China', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jin Jong-O', age: 24, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marko Kemppainen', age: 28, country: 'Finland', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Jong-Su', age: 27, country: 'North Korea', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olena Kostevych', age: 19, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katerina Kurková-Emmons', age: 20, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Manfred Kurzer', age: 34, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Li Jie', age: 31, country: 'China', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christian Lusch', age: 23, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dmitry Lykin', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Martynov', age: 36, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zemfira Meft?kh?tddinova', age: 41, country: 'Azerbaijan', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giovanni Pellielo', age: 34, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christian Planer', age: 29, country: 'Austria', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Polyakov', age: 36, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'María Quintanal', age: 34, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rajyavardhan Rathore', age: 34, country: 'India', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Rhode', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Juan Miguel Rodríguez', age: 37, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ralf Schumann', age: 42, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jasna Šekaric', age: 38, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valentina Turisini', age: 35, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adam Vella', age: 33, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Chengyi', age: 21, country: 'China', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Yifu', age: 43, country: 'China', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wang Zheng', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wei Ning', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhu Qinan', age: 19, country: 'China', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fehaid Al-Deehani', age: 33, country: 'Kuwait', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yevgeny Aleynikov', age: 33, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Alifirenko', age: 41, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michel Ansermet', age: 35, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cai Yalin', age: 23, country: 'China', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rajmond Debevec', age: 37, country: 'Slovenia', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michael Diamond', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Franck Dumoulin', age: 28, country: 'France', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Svetlana Dyomina', age: 39, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jonas Edman', age: 33, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Richard Faulds', age: 23, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariya Feklistova', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Annemarie Forder', age: 22, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gang Cho-Hyeon', age: 17, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gao E', age: 37, country: 'China', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gao Jing', age: 24, country: 'China', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Deborah Gelisio', age: 24, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tatyana Goldobina', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Todd Graves', age: 37, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Torben Grimmel', age: 24, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Grozdeva', age: 28, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daina Gudzineviciute', age: 34, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pia Hansen', age: 34, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Juha Hirvi', age: 40, country: 'Finland', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Diána Igaly', age: 35, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Artyom Khadzhibekov', age: 30, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tanyu Kiryakov', age: 37, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Petr Málek', age: 38, country: 'Czech Republic', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Russell Mark', age: 36, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Martynov', age: 32, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Renata Mauer-Rózanska', age: 31, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zemfira Meft?kh?tddinova', age: 37, country: 'Azerbaijan', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mykola Milchev', age: 32, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lalita Milshina-Yauhleuskaya', age: 36, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oleg Moldovan', age: 33, country: 'Moldova', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nancy Napolski-Johnson', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Niu Zhiyuan', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ian Peel', age: 42, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Giovanni Pellielo', age: 30, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Delphine Racinet-Reau', age: 26, country: 'France', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iulian Raicea', age: 27, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Rhode', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jasna Šekaric', age: 34, country: 'Serbia and Montenegro', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Harald Stenvaag', age: 47, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martin Tenk', age: 28, country: 'Czech Republic', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Yifu', age: 39, country: 'China', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yang Ling', age: 28, country: 'China', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ben Ainslie', age: 35, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marina Alabau', age: 26, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jo Aleh', age: 26, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mathew Belcher', age: 29, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lobke Berkhout', age: 31, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stuart Bithell', age: 25, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marit Bouwmeester', age: 24, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Peter Burling', age: 21, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lucas Calabrese', age: 25, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Saskia Clark', age: 32, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nina Curtis', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juan de la Fuente', age: 35, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nick Dempsey', age: 31, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Támara Echegoyen', age: 28, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jonas Høgh Christensen', age: 31, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iain Jensen', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Silja Kanerva', age: 27, country: 'Finland', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pavlos Kontides', age: 22, country: 'Cyprus', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Peter Lang', age: 23, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Silja Lehtinen', age: 26, country: 'Finland', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jonathan Lobert', age: 27, country: 'France', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fredrik Lööf', age: 42, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Przemyslaw Miarczynski', age: 32, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hannah Mills', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rasmus Myrgren', age: 33, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zofia Noceti-Klepacka', age: 26, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Allan Nørregaard', age: 31, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nathan Outteridge', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Malcolm Page', age: 40, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luke Patience', age: 25, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iain Percy', age: 36, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tuuli Petäjä', age: 28, country: 'Finland', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olivia Powrie', age: 24, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bruno Prada', age: 40, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olivia Price', age: 19, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Angela Pumariega', age: 27, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Max Salminen', age: 23, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Robert Scheidt', age: 39, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrew Simpson', age: 35, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tom Slingsby', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sofia Toro', age: 21, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Blair Tuke', age: 23, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Evi Van Acker', age: 26, country: 'Belgium', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dorian van Rijsselberge', age: 23, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lisa Westerhof', age: 30, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lucinda Whitty', age: 22, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mikaela Wulff', age: 22, country: 'Finland', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xu Lijia', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ben Ainslie', age: 31, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Glenn Ashby', age: 30, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tom Ashley', age: 24, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Ayton', age: 28, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olivier Bausset', age: 26, country: 'France', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sofia Bekatorou', age: 30, country: 'Greece', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lobke Berkhout', age: 27, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Annemieke Bes', age: 30, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julien Bontemps', age: 29, country: 'France', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marcelien Bos-de Koning', age: 30, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Darren Bundock', age: 37, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicolas Charbonnier', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fernando Echavarri', age: 36, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anders Ekström', age: 27, country: 'Sweden', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carlos Espínola', age: 36, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xavier Fernández', age: 31, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Guillaume Florent', age: 34, country: 'France', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joe Glanfield', age: 29, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paul Goodison', age: 30, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Martin Kirketerp', age: 36, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Virginia Kravarioti', age: 24, country: 'Greece', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Santiago Lange', age: 46, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fredrik Lööf', age: 38, country: 'Sweden', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iker Martínez', age: 31, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mandy Mulder', age: 21, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fernanda Oliveira', age: 27, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Malcolm Page', age: 36, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sofia Papadopoulou', age: 24, country: 'Greece', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tessa Parkinson', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antón Paz', age: 32, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hannes Peckolt', age: 25, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jan Peter Peckolt', age: 27, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iain Percy', age: 32, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bruno Prada', age: 37, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zach Railey', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elise Rechichi', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nick Rogers', age: 31, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Diego Romero', age: 33, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robert Scheidt', age: 35, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alessandra Sensini', age: 38, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bryony Shaw', age: 25, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrew Simpson', age: 31, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Isabel Swan', age: 24, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Tunnicliffe', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gintare Volungeviciute-Scheidt', age: 25, country: 'Lithuania', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jonas Warrer', age: 29, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Webb', age: 31, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nathan Wilmot', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pippa Wilson', age: 22, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Merel Witteveen', age: 23, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Xu Lijia', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yin Jian', age: 29, country: 'China', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vasilij Žbogar', age: 32, country: 'Slovenia', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shahar Zubari', age: 21, country: 'Israel', year: 2008, date: '24/08/2008', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ben Ainslie', age: 27, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Ayton', age: 24, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sandra Azón', age: 30, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sofia Bekatorou', age: 26, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kevin Burnham', age: 47, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nick Dempsey', age: 24, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chris Draper', age: 26, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carlos Espínola', age: 32, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xavier Fernández', age: 27, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marcelo Ferreira', age: 38, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paul Foerster', age: 40, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gal Fridman', age: 28, country: 'Israel', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andreas Geritzer', age: 26, country: 'Austria', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joe Glanfield', age: 25, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Torben Grael', age: 44, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roman Hagara', age: 38, country: 'Austria', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Simon Hiscocks', age: 31, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dorte Jensen', age: 31, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Helle Jespersen', age: 36, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikos Kaklamanakis', age: 35, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hanna Kalinina', age: 25, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mateusz Kusznierewicz', age: 29, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Santiago Lange', age: 42, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Heorhiy Leonchuk', age: 30, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Signe Livbjerg', age: 24, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'John Lovell', age: 36, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rodion Luka', age: 31, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ross MacDonald', age: 39, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iker Martínez', age: 27, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Svitlana Matevusheva', age: 23, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Faustine Merret', age: 26, country: 'France', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Charlie Ogletree', age: 36, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christina Otzen', age: 28, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pascal Rambeau', age: 32, country: 'France', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shirley Robertson', age: 36, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nick Rogers', age: 27, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Xavier Rohart', age: 36, country: 'France', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robert Scheidt', age: 31, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kazuto Seki', age: 28, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alessandra Sensini', age: 34, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lenka Šmídová', age: 29, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hans-Peter Steinacher', age: 35, country: 'Austria', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Siren Sundby', age: 21, country: 'Norway', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ruslana Taran', age: 33, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kenjiro Todoroki', age: 28, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Therese Torgersson', age: 28, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rafael Trujillo', age: 28, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aimilia Tsoulfa', age: 31, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Natalia Vía Dufresne', age: 31, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sarah Webb', age: 27, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mike Wolfs', age: 33, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yin Jian', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vendela Zachrisson-Santén', age: 26, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vasilij Žbogar', age: 28, country: 'Slovenia', year: 2004, date: '29/08/2004', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ben Ainslie', age: 23, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Serena Amato', age: 26, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jenny Armstrong', age: 30, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gunnar Bahr', age: 25, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jesper Bank', age: 43, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ian Barker', age: 34, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Blackburn', age: 30, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Henrik Blakskjær', age: 29, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ingo Borkowski', age: 28, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Darren Bundock', age: 29, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Javier Conte', age: 25, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mark Covell', age: 32, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paul Davis', age: 42, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Juan de la Fuente', age: 24, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Luca Devoti', age: 37, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carlos Espínola', age: 28, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marcelo Ferreira', age: 34, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paul Foerster', age: 36, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'John Forbes', age: 30, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roland Gäbler', age: 35, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pease Glaser', age: 38, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Torben Grael', age: 40, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roman Hagara', age: 34, country: 'Austria', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Simon Hiscocks', age: 27, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'JJ Isler', age: 36, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Thomas Jacobsen', age: 28, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jyrki Järvi', age: 34, country: 'Finland', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Herman Horn Johannessen', age: 36, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thomas Johanson', age: 31, country: 'Finland', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Barbara Kendall', age: 33, country: 'New Zealand', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tom King', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Magnus Liljedahl', age: 46, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fredrik Lööf', age: 30, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Amelie Lux', age: 23, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Margriet Matthijsse', age: 23, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aaron McIntosh', age: 28, country: 'New Zealand', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Charlie McKee', age: 38, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jonathan McKee', age: 40, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bob Merrick', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olena Pakholchyk', age: 35, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iain Percy', age: 24, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Reynolds', age: 44, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shirley Robertson', age: 32, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Robert Scheidt', age: 27, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jochen Schümann', age: 46, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'René Schwall', age: 29, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alessandra Sensini', age: 30, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christoph Sieber', age: 29, country: 'Austria', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hans-Peter Steinacher', age: 32, country: 'Austria', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Espen Stokkeland', age: 32, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Belinda Stowell', age: 29, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ruslana Taran', age: 29, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mark Turnbull', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ian Walker', age: 30, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Sailing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chantal Achterberg', age: 27, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Filip Adamski', age: 29, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carina Bär', age: 22, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jacob Barsøe', age: 23, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chris Bartley', age: 28, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Romano Battisti', age: 25, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anna Bebington-Watkins', age: 29, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Claudia Belderbos', age: 27, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gabe Bergen', age: 30, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hamish Bond', age: 26, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carline Bouw', age: 27, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matthew Brittain', age: 25, country: 'South Africa', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeremiah Brown', age: 26, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ashley Brzozowicz', age: 29, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrew Byrnes', age: 29, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Erin Cafaro', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alan Campbell', age: 29, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peter Chambers', age: 22, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Richard Chambers', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'James Chapman', age: 32, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Germain Chardin', age: 29, country: 'France', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nathan Cohen', age: 26, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Charlie Cole', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iztok Cop', age: 40, country: 'Slovenia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kat Copeland', age: 21, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Will Crothers', age: 25, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Douglas Csima', age: 26, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Caryn Davies', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sytske de Groot', age: 26, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Annemiek de Haan', age: 31, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rachelle De Jong-Viinberg', age: 33, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Natalie Dell', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yana Dementieva', age: 33, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nataliya Dovhodko', age: 21, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mahé Drysdale', age: 33, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Joshua Dunkley-Smith', age: 23, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eskild Ebbesen', age: 40, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ric Egington', age: 33, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fie Udby Erichsen', age: 27, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'James Foad', age: 25, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karsten Forsterling', age: 32, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Susan Francia', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Magdalena Fularczyk', age: 25, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Scott Gault', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Khristina Giazitzidou', age: 22, country: 'Greece', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rob Gibson', age: 26, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Drew Ginn', age: 37, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Helen Glover', age: 26, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katherine Grainger', age: 36, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alex Gregory', age: 28, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tim Grohmann', age: 23, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Krista Guloien', age: 32, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juliette Haigh', age: 29, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Janine Hanson', age: 29, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Phelan Hill', age: 33, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kate Hornsey', age: 30, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sophie Hosking', age: 26, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Malcolm Howard', age: 29, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Huang Wenyi', age: 21, country: 'China', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mark Hunter', age: 34, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tom James', age: 28, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eric Johannesen', age: 24, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Morten Jørgensen', age: 27, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Megan Kalmoe', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nienke Kingma', age: 30, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mirka Knapková', age: 31, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kara Kohler', age: 21, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anastasiya Kozhenkova', age: 26, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andreas Kuffner', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt Langridge', age: 29, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Caroline Lind', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'William Lockwood', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Esther Lofgren', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elle Logan', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Constantine Louloudis', age: 20, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Darcy Marquardt', age: 33, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adrienne Martelli', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Damir Martin', age: 24, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Natalie Mastracci', age: 23, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Conlin McCabe', age: 21, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'James McRae', age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Florian Mennigen', age: 30, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Julia Michalska', age: 27, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chris Morgan', age: 29, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andréanne Morin', age: 30, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dorian Mortelette', age: 28, country: 'France', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lukas Müller', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eric Murray', age: 30, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Meghan Musnicki', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'George Nash', age: 22, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sizwe Ndlovu', age: 31, country: 'South Africa', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniel Noonan', age: 32, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Glenn Ochal', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Britta Oppelt', age: 34, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sarah Outhwaite-Tait', age: 29, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alex Partridge', age: 31, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brooke Pratley', age: 32, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brian Price', age: 36, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zac Purchase', age: 26, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rasmus Quist', age: 32, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tom Ransley', age: 26, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mads Rasmussen', age: 30, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pete Reed', age: 31, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maximilian Reinelt', age: 23, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roline Repelaer van Driel', age: 28, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Julia Richter', age: 23, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Taylor Ritzel', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Henrik Rummel', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Šain', age: 24, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alessio Sartori', age: 35, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Will Satch', age: 23, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martin Sauer', age: 29, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Moe Sbihi', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anne Schellekens', age: 26, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Richard Schmidt', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lauritz Schoof', age: 21, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karl Schulze', age: 24, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rebecca Scown', age: 28, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Greg Searle', age: 40, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martin Sinkovic', age: 22, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valent Sinkovic', age: 23, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'John Smith', age: 22, country: 'South Africa', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luka Špik', age: 33, country: 'Slovenia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Heather Stanning', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Joseph Sullivan', age: 25, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ondrej Synek', age: 29, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kateryna Tarasenko', age: 24, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Taylor', age: 28, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Annekatrin Thiele', age: 27, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'James Thompson', age: 25, country: 'South Africa', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lesley Thompson-Willie', age: 52, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrew Triggs Hodge', age: 33, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alexandra Tsiavou', age: 26, country: 'Greece', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Storm Uru', age: 27, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jacobine Veenhoven', age: 28, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Phillipp Wende', age: 27, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mary Whipple', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristof Wilke', age: 27, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lauren Wilkinson', age: 22, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rob Williams', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kasper Winther Jørgensen', age: 27, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xu Dongxiang', age: 29, country: 'China', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luca Agamennoni', age: 28, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wyatt Allen', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mads Andersen', age: 30, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Julien Bahain', age: 22, country: 'France', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eniko Barabas-Mironcic', age: 22, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jon Beare', age: 34, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Bebington-Watkins', age: 25, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Milosz Bernatajtys', age: 26, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cédric Berrest', age: 23, country: 'France', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuliya Bichik', age: 25, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kathrin Boron', age: 38, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Micah Boyd', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iain Brambell', age: 34, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Scott Brennan', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'George Bridgewater', age: 25, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrew Byrnes', age: 25, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erin Cafaro', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dave Calder', age: 30, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tracy Cameron', age: 33, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Germain Chardin', age: 25, country: 'France', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jonathan Coeffic', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Steven Coppola', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Crawshay', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Caryn Davies', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Annemiek de Haan', age: 27, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Femke Dekker', age: 29, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julien Després', age: 25, country: 'France', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mahé Drysdale', age: 29, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rumyana Dzhadzharova-Neykova', age: 35, country: 'Bulgaria', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eskild Ebbesen', age: 36, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thomas Ebert', age: 35, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ric Egington', age: 29, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tõnu Endrekson', age: 29, country: 'Estonia', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Caroline Evers-Swindell', age: 29, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Georgina Evers-Swindell', age: 29, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Debbie Flood', age: 28, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rodica Florea-Serban', age: 25, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Susan Francia', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Scott Frandsen', age: 28, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Duncan Free', age: 35, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rossano Galtarossa', age: 36, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gao Yulan', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nataliya Gelakh', age: 30, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Elena Georgescu', age: 44, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Drew Ginn', age: 33, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Goodale', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katherine Grainger', age: 32, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michelle Guerette', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kyle Hamilton', age: 30, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alastair Heathcote', age: 30, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Francis Hegerty', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Beau Hoopman', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Frances Houghton', age: 27, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Malcolm Howard', age: 25, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Hunter', age: 30, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christiane Huth', age: 27, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Doina Ignat', age: 39, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Josh Inman', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jüri Jaanson', age: 42, country: 'Estonia', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tom James', age: 24, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michal Jelinski', age: 28, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jin Ziwei', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Morten Jørgensen', age: 23, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yekaterina Khodatovich-Karsten', age: 36, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nienke Kingma', age: 26, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Melanie Kok', age: 24, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marek Kolbowicz', age: 37, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adam Korol', age: 33, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adam Kreek', age: 27, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt Langridge', age: 25, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elise Laverick', age: 33, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mike Lewis', age: 27, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kevin Light', age: 29, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Caroline Lind', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elle Logan', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tom Lucy', age: 20, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Manuela Lutze', age: 34, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'James Marburg', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marcus McElhenney', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maxi McKenzie-McHarg', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anna Mickelson-Cummins', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dorian Mortelette', age: 24, country: 'France', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dimitris Mougios', age: 26, country: 'Greece', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Acer Nethercott', age: 30, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Minna Nieminen', age: 31, country: 'Finland', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Britta Oppelt', age: 30, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ioana Papuc-Rotaru', age: 24, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Liam Parsons', age: 31, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alex Partridge', age: 27, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bartlomiej Pawelczak', age: 26, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lukasz Pawlowski', age: 25, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pierre-Jean Peltier', age: 24, country: 'France', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Constanta Pipota-Burcica', age: 37, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vasilios Polymeros', age: 32, country: 'Greece', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brian Price', age: 32, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zac Purchase', age: 22, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rasmus Quist', age: 28, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simone Raineri', age: 31, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pawel Randa', age: 29, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mads Rasmussen', age: 26, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pete Reed', age: 27, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roline Repelaer van Driel', age: 24, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Benjamin Rondeau', age: 24, country: 'France', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stephen Rowbotham', age: 26, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ben Rutledge', age: 27, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt Ryan', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stephanie Schiller', age: 22, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matt Schnobrich', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lindsay Schoop', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dominic Seiterle', age: 32, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Siegelaar', age: 26, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Colin Smith', age: 24, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marlies Smulders', age: 26, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tom Stallard', age: 29, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sanna Stén', age: 31, country: 'Finland', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Simona Strimbeschi-Musat', age: 26, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ondrej Synek', age: 25, country: 'Czech Republic', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tang Bin', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Helen Tanger', age: 29, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Annekatrin Thiele', age: 23, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrew Triggs Hodge', age: 29, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olaf Tufte', age: 32, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nathan Twaddle', age: 31, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kirsten van der Kolk', age: 32, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marit van Eupen', age: 38, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Annemarieke van Rumpt', age: 28, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Simone Venier', age: 23, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Annie Vernon', age: 25, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bryan Volpenhein', age: 31, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniel Walsh', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Konrad Wasielewski', age: 23, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt Wells', age: 28, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Josh West', age: 31, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jake Wetzel', age: 31, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mary Whipple', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Steve Williams', age: 32, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ester Workel', age: 33, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wu You', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Xi Aihua', age: 26, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Yangyang', age: 19, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luca Agamennoni', age: 24, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chris Ahrens', age: 28, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wyatt Allen', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Catello Amarante', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Salvatore Amitrano', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cam Baerg', age: 31, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michiel Bartman', age: 37, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dan Beery', age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lorenzo Bertini', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuliya Bichik', age: 21, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Serhiy Biloushchenko', age: 22, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cath Bishop', age: 32, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Claudia Blasberg', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kathrin Boron', age: 34, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Amber Bradley', age: 24, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simon Burgess', age: 36, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Donnie Cech', age: 30, country: 'South Africa', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chun Wei Cheung', age: 32, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aurica Chirita-Barascu', age: 29, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pete Cipollone', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ed Coode', age: 29, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Iztok Cop', age: 32, country: 'Slovenia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alison Cox', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'James Cracknell', age: 32, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ben Cureton', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Caryn Davies', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Annemiek de Haan', age: 23, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matt Deakin', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hurnet Dekkers', age: 30, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dario Dentale', age: 21, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Geert-Jan Derksen', age: 29, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ramon di Clemente', age: 29, country: 'South Africa', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Megan Dirkmaat', age: 28, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Frédéric Dufour', age: 28, country: 'France', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rumyana Dzhadzharova-Neykova', age: 31, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eskild Ebbesen', age: 32, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thomas Ebert', age: 31, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anthony Edwards', age: 31, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gerritjan Eggenkamp', age: 28, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Meike Evers', age: 27, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Caroline Evers-Swindell', age: 25, country: 'New Zealand', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Georgina Evers-Swindell', age: 25, country: 'New Zealand', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dana Faletic', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Fedorovtsev', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Debbie Flood', age: 24, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rodica Florea-Serban', age: 21, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jan-Willem Gabriëls', age: 25, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liliana Gafencu', age: 29, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rossano Galtarossa', age: 32, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Gelakh', age: 26, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Elena Georgescu', age: 40, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Drew Ginn', age: 29, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katherine Grainger', age: 28, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jakub Hanák', age: 21, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joey Hansen', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bo Hanson', age: 31, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adrien Hardy', age: 26, country: 'France', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tom Herschmiller', age: 26, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nienke Hommes', age: 27, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Beau Hoopman', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kerry Hore', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Frances Houghton', age: 23, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Serhiy Hryn', age: 22, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Doina Ignat', age: 35, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jüri Jaanson', age: 38, country: 'Estonia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'David Jirka', age: 22, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katie Johnson', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tomáš Karas', age: 29, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yekaterina Khodatovich-Karsten', age: 32, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'David Kopriva', age: 24, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laurel Korholz', age: 34, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kerstin Kowalski-El-Qalqili', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Igor Kravtsov', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thor Kristensen', age: 24, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tomasz Kucharski', age: 30, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elise Laverick', age: 29, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Raffaello Leonardo', age: 31, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Glen Loftus', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Manuela Lutze', age: 30, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Oleh Lykov', age: 31, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sam Magee', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bruno Mascarenhas', age: 23, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mike McKay', age: 39, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniël Mensch', age: 25, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anna Mickelson-Cummins', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alison Mowbray', age: 33, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stephan Mølvig', age: 25, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lianne Nelson', age: 32, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elisabeta Oleniuc-Lipa', age: 39, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Britta Oppelt', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ioana Papuc-Rotaru', age: 20, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matthew Pinsent', age: 33, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Constanta Pipota-Burcica', age: 33, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vasilios Polymeros', age: 28, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lorenzo Porzio', age: 22, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jason Read', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniela Reimer', age: 21, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stuart Reside', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rebecca Romero', age: 24, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katrin Rutschow-Stomporowski', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alessio Sartori', age: 27, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rebecca Sattin', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leonid Shaposhnykov', age: 34, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sarah Siegelaar', age: 22, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Diederik Simon', age: 34, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikša Skelin', age: 26, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Siniša Skelin', age: 30, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikos Skiathitis', age: 22, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marlies Smulders', age: 22, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Luka Špik', age: 25, country: 'Slovenia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikolay Spinev', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Geoff Stewart', age: 30, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'James Stewart', age: 30, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Steve Stewart', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Svirin', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Robert Sycz', age: 30, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stefan Szczurowski', age: 22, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Angela Tamas-Alupei', age: 32, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Helen Tanger', age: 25, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'James Tomkins', age: 38, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michael Toon', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pascal Touron', age: 31, country: 'France', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olaf Tufte', age: 28, country: 'Norway', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kirsten van der Kolk', age: 28, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marit van Eupen', age: 34, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Annemarieke van Rumpt', age: 24, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matthijs Vellenga', age: 26, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gijs Vermeulen', age: 23, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sébastien Vielledent', age: 27, country: 'France', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bryan Volpenhein', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peggy Waleska', age: 24, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Froukje Wegman', age: 25, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stuart Welch', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jake Wetzel', age: 27, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mary Whipple', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Barney Williams', age: 27, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steve Williams', age: 28, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Winckless', age: 30, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ester Workel', age: 29, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ivo Yanakiev', age: 28, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Agostino Abbagnale', age: 34, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Buffy Alexander-Williams', age: 23, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michel Andrieux', age: 33, country: 'France', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tessa Appeldoorn', age: 27, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Louis Attrill', age: 25, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Darren Balmforth', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michiel Bartman', age: 33, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Guin Batten', age: 32, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Miriam Batten', age: 35, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sebastian Bea', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fredrik Bekken', age: 25, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jean-Christophe Bette', age: 22, country: 'France', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Laryssa Biesenthal', age: 29, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Claudia Blasberg', age: 25, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Igor Boraska', age: 29, country: 'Croatia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kathrin Boron', age: 30, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Simon Burgess', age: 33, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dan Burke', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Giovanni Calabrese', age: 33, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lorenzo Carboncini', age: 23, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Thibaud Chapelle', age: 23, country: 'France', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Veronica Cogeanu-Cochelea', age: 34, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christine Collins', age: 31, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iztok Cop', age: 28, country: 'Slovenia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'James Cracknell', age: 28, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Krešimir Culjak', age: 30, country: 'Croatia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Heather Davis', age: 26, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Riccardo Dei Rossi', age: 31, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Simon Dennis', age: 24, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ben Dodwell', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xavier Dorfmann', age: 27, country: 'France', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Oksana Dorodnova', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rowley Douglas', age: 23, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maria Dumitrache', age: 23, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rumyana Dzhadzharova-Neykova', age: 27, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eskild Ebbesen', age: 28, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thomas Ebert', age: 27, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anthony Edwards', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Meike Evers', age: 23, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Victor Feddersen', age: 32, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Fedotova', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jaime Fernandez', age: 29, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tim Foster', age: 30, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Igor Francetic', age: 23, country: 'Croatia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tihomir Frankovic', age: 29, country: 'Croatia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Liliana Gafencu', age: 25, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rossano Galtarossa', age: 28, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Garner', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marco Geisler', age: 26, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Elena Georgescu', age: 36, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alastair Gordon', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katherine Grainger', age: 24, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luka Grubor', age: 26, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marcel Hacker', age: 23, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreas Hajek', age: 32, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bo Hanson', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brett Hayman', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yves Hocdé', age: 27, country: 'France', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ben Hunt-Davis', age: 28, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rob Jahrling', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yekaterina Khodatovich-Karsten', age: 28, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alison Korn', age: 29, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Manja Kowalski', age: 24, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kerstin Kowalski-El-Qalqili', age: 24, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karen Kraft', age: 31, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tomasz Kucharski', age: 26, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yuliya Levina', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrew Lindsay', age: 23, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gillian Lindsay', age: 26, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dirk Lippits', age: 23, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Matthew Long', age: 25, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Elia Luini', age: 21, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Theresa Luke', age: 33, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Manuela Lutze', age: 26, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Søren Madsen', age: 24, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Heather McDermid', age: 31, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mike McKay', age: 35, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elien Meijer', age: 30, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Larisa Merk', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Valter Molea', age: 34, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carlo Mornati', age: 28, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Xeno Müller', age: 28, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ted Murphy', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elisabeta Oleniuc-Lipa', age: 35, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ioana Olteanu', age: 34, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nelleke Penninx', age: 29, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Silvijo Petriško', age: 20, country: 'Croatia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leonardo Pettinari', age: 27, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Matthew Pinsent', age: 29, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Constanta Pipota-Burcica', age: 29, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristina Poplavskaja', age: 29, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laurent Porchier', age: 32, country: 'France', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nick Porzig', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martijntje Quik', age: 26, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Simone Raineri', age: 23, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Steven Redgrave', age: 38, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Robert Richards', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Emma Robinson', age: 28, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jean-Christophe Rolland', age: 32, country: 'France', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katrin Rutschow-Stomporowski', age: 25, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christian Ryan', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Birute Šakickiene', age: 31, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alessio Sartori', age: 23, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicola Sartori', age: 24, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fred Scarlett', age: 25, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Missy Schwen-Ryan', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Diederik Simon', age: 30, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikša Skelin', age: 22, country: 'Croatia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Siniša Skelin', age: 26, country: 'Croatia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kate Slatter', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tomislav Smoljanovic', age: 23, country: 'Croatia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Luka Špik', age: 21, country: 'Slovenia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Geoff Stewart', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'James Stewart', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Viorica Susanu', age: 24, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Robert Sycz', age: 26, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Angela Tamas-Alupei', age: 28, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rachael Taylor', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carin ter Beek', age: 29, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jana Thieme', age: 30, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lesley Thompson-Willie', age: 40, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'James Tomkins', age: 35, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pascal Touron', age: 27, country: 'France', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Steve Trapmore', age: 25, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olaf Tufte', age: 24, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dorota Urbaniak', age: 28, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anneke Venema', age: 29, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jochem Verberne', age: 22, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valerie Viehoff', age: 24, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stephan Volkert', age: 29, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Branimir Vujevic', age: 25, country: 'Croatia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rob Waddell', age: 25, country: 'New Zealand', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stuart Welch', age: 22, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kieran West', age: 23, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marieke Westerhof', age: 26, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'André Willms', age: 28, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Elisa Blanchi', age: 24, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anastasiya Bliznyuk', age: 18, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lyubov Cherkashina', age: 24, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Darya Dmitriyeva', age: 19, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ulyana Donskova', age: 19, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kseniya Dudkina', age: 17, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marina Goncharova', age: 22, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anastasiya Ivankova', age: 20, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yevgeniya Kanayeva', age: 22, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Romina Laurito', age: 25, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Leshchik', age: 17, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alina Makarenko', age: 17, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandra Narkevich', age: 17, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anastasiya Nazarenko', age: 19, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marta Pagnini', age: 21, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kseniya Sankovich', age: 22, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elisa Santoni', age: 24, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Angelica Savrayuk', age: 22, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karolina Sevastyanova', age: 17, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andreea Stefanescu', age: 18, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alina Tumilovich', age: 22, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Margarita Aliychuk', age: 18, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alesya Babushkina', age: 19, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hanna Bezsonova', age: 24, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cai Tongtong', age: 18, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chou Tao', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anna Gavrilenko', age: 18, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatyana Gorbunova', age: 18, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anastasiya Ivankova', age: 16, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yevgeniya Kanayeva', age: 18, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lu Yuanyang', age: 25, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zina Lunina', age: 19, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Glafira Martinovich', age: 19, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Posevina', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kseniya Sankovich', age: 18, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Darya Shkurikhina', age: 17, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sui Jianshuang', age: 19, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sun Dan', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alina Tumilovich', age: 18, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhang Shuo', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Inna Zhukova', age: 21, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nataliya Zuyeva', age: 19, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olesya Belugina', age: 20, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hanna Bezsonova', age: 20, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Elisa Blanchi', age: 16, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Irina Chashchina', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Fabrizia D'Ottavio", age: 19, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marinella Falca', age: 18, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olga Glatskikh', age: 15, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhaneta Ilieva', age: 19, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alina Kabayeva', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ele?nora Kezhova', age: 18, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatyana Kurbakova', age: 18, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nataliya Lavrova', age: 20, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zornitsa Marinova', age: 17, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniela Masseroni', age: 19, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Murzina', age: 20, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yelena Posevina', age: 18, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristina Rangelova', age: 19, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Elisa Santoni', age: 16, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Galina Tancheva', age: 17, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vladislava Tancheva', age: 17, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura Vernizzi', age: 18, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tatyana Ananko', age: 16, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eirini A?ndili', age: 17, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuliya Barsukova', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatyana Belan', age: 17, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Irina Belova', age: 19, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maria Georgatou', age: 16, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Glazkova', age: 19, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Irina Ilenkova', age: 20, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alina Kabayeva', age: 17, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zara Karyami', age: 17, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eva Khristodoulou', age: 17, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Lavrova', age: 16, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariya Lazuk', age: 16, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Netesova', age: 17, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kharikleia Pantazi', age: 15, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Polatou', age: 16, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olga Puzhevich', age: 17, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuliya Raskina', age: 18, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Shalamova', age: 18, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vera Shimanskaya', age: 19, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irina Zilber', age: 16, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Rhythmic Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brett Camerota', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tino Edelmann', age: 24, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eric Frenzel', age: 21, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Felix Gottwald', age: 34, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Björn Kircheisen', age: 26, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Kreiner', age: 28, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jason Lamy-Chappuis', age: 23, country: 'France', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Todd Lodwick', age: 33, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alessandro Pittin', age: 20, country: 'Italy', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Johannes Rydzek', age: 18, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mario Stecher', age: 32, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ronny Ackermann', age: 28, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christoph Bieler', age: 28, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jens Gaiser', age: 27, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Gruber', age: 26, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Björn Kircheisen', age: 22, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anssi Koivuranta', age: 17, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Antti Kuisma', age: 27, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hannu Manninen', age: 27, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mario Stecher', age: 28, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jaakko Tallus', age: 24, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christoph Bieler', age: 24, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michael Gruber', age: 22, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Georg Hettich', age: 23, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marcel Höhlig', age: 22, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Björn Kircheisen', age: 18, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hannu Manninen', age: 23, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jari Mantila', age: 30, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mario Stecher', age: 24, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura Asadauskaite', age: 28, country: 'Lithuania', year: 2012, date: '12/08/2012', sport: 'Modern Pentathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cao Zhongrong', age: 30, country: 'China', year: 2012, date: '12/08/2012', sport: 'Modern Pentathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ádám Marosi', age: 28, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Modern Pentathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yane Marques', age: 28, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Modern Pentathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Samantha Murray', age: 22, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Modern Pentathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'David Svoboda', age: 27, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Modern Pentathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Heather Fell', age: 25, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Modern Pentathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Edvinas Krungolcas', age: 35, country: 'Lithuania', year: 2008, date: '24/08/2008', sport: 'Modern Pentathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrey Moiseyev', age: 29, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Modern Pentathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lena Schöneborn', age: 22, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Modern Pentathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Viktoriya Tereshchuk', age: 26, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Modern Pentathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrejus Zadneprovskis', age: 33, country: 'Lithuania', year: 2008, date: '24/08/2008', sport: 'Modern Pentathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Libor Capalini', age: 31, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Modern Pentathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Georgina Harland', age: 26, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Modern Pentathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrey Moiseyev', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Modern Pentathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jelena Rublevska', age: 28, country: 'Latvia', year: 2004, date: '29/08/2004', sport: 'Modern Pentathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zsuzsa Voros', age: 27, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Modern Pentathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrejus Zadneprovskis', age: 29, country: 'Lithuania', year: 2004, date: '29/08/2004', sport: 'Modern Pentathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kate Allenby', age: 26, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Modern Pentathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gábor Balogh', age: 24, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Modern Pentathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steph Cook', age: 28, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Modern Pentathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emily deRiel', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Modern Pentathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pavel Dovgal', age: 24, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Modern Pentathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dmitry Svatkovsky', age: 28, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Modern Pentathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Natalie Geisenberger', age: 22, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatjana Hüfner', age: 26, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Patric Leitner', age: 32, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreas Linger', age: 28, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wolfgang Linger', age: 27, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Felix Loch', age: 20, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Möller', age: 28, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nina Reithmayer', age: 25, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexander Resch', age: 30, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andris Šics', age: 24, country: 'Latvia', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juris Šics', age: 26, country: 'Latvia', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Armin Zöggeler', age: 36, country: 'Italy', year: 2010, date: '28/02/2010', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Albert Demchenko', age: 34, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'André Florschütz', age: 29, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oswald Haselrieder', age: 34, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatjana Hüfner', age: 22, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Silke Kraushaar', age: 35, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andreas Linger', age: 24, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wolfgang Linger', age: 23, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sylke Otto', age: 36, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gerhard Plankensteiner', age: 34, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martinš Rubenis', age: 27, country: 'Latvia', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Torsten Wustlich', age: 29, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Armin Zöggeler', age: 32, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Grimmette', age: 31, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Georg Hackl', age: 35, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Clay Ives', age: 29, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Silke Kraushaar', age: 31, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Patric Leitner', age: 24, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brian Martin', age: 28, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Barbara Niedernhuber', age: 27, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sylke Otto', age: 32, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Markus Prock', age: 37, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alexander Resch', age: 22, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Thorpe', age: 31, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Armin Zöggeler', age: 28, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Luge', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yuri Alvear', age: 26, country: 'Colombia', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'An Kum-Ae', age: 32, country: 'North Korea', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yanet Bermoy', age: 25, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ole Bischof', age: 32, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Edith Bosch', age: 32, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karina Bryant', age: 33, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Corina Caprioriu', age: 26, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Éva Csernoviczki', age: 25, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rafael da Silva', age: 25, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lucie Décosse', age: 30, country: 'France', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alina Dumitru', age: 29, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Masashi Ebinuma', age: 22, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gevrise Emane', age: 30, country: 'France', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rosalba Forciniti', age: 26, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Arsen Galstyan', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gemma Gibbons', age: 25, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Priscilla Gneto', age: 20, country: 'France', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Asley González', age: 22, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Henk Grol', age: 27, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kayla Harrison', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hiroaki Hiraoka', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ilias Iliadis', age: 25, country: 'Greece', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mansur Isayev', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jo Jun-Ho', age: 23, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tagir Khaybulayev', age: 28, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Jae-Beom', age: 27, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Felipe Kitadai', age: 23, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ugo Legrand', age: 23, country: 'France', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marti Malloy', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kaori Matsumoto', age: 24, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Menezes', age: 22, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Mikhaylin', age: 32, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Naidangiin Tüvshinbayar', age: 28, country: 'Mongolia', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Riki Nakaya', age: 23, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ivan Nifontov', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Masashi Nishiyama', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Idalys Ortíz', age: 22, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Automne Pavia', age: 23, country: 'France', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dimitri Peters', age: 28, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Teddy Riner', age: 23, country: 'France', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Saynjargalyn Nyam-Ochir', age: 26, country: 'Mongolia', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lasha Shavdatuashvili', age: 20, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mayra Silva', age: 20, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rishod Sobirov', age: 25, country: 'Uzbekistan', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Song Dae-Nam', age: 33, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mika Sugimoto', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Audrey Tcheumeo', age: 22, country: 'France', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kerstin Thiele', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andreas Tölzer', age: 32, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tong Wen', age: 29, country: 'China', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yoshie Ueno', age: 29, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Miklós Ungvári', age: 31, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Antoine Valois-Fortier', age: 22, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Charline Van Snick', age: 21, country: 'Belgium', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xu Lili', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Urška Žolnir', age: 30, country: 'Slovenia', year: 2012, date: '12/08/2012', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'An Kum-Ae', age: 28, country: 'North Korea', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yordanis Arencibia', age: 28, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergei Aschwanden', age: 32, country: 'Switzerland', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Amar Benikhlef', age: 26, country: 'Algeria', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yanet Bermoy', age: 21, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ole Bischof', age: 28, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rasul Bokiyev', age: 25, country: 'Tajikistan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Edith Bosch', age: 28, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oscar Braison', age: 23, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tiago Camilo', age: 26, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yalennis Castillo', age: 22, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Choi Min-Ho', age: 27, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Benjamin Darbelet', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lucie Décosse', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alina Dumitru', age: 25, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Deborah Gravenstijn', age: 33, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Henk Grol', age: 23, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leandro Guilheiro', age: 25, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Soraya Haddad', age: 23, country: 'Algeria', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anaisis Hernández', age: 26, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roman Hontiuk', age: 24, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ruben Houkes', age: 29, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Satoshi Ishii', age: 21, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeong Gyeong-Mi', age: 23, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Jae-Beom', age: 23, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mövlud Mir?liyev', age: 34, country: 'Azerbaijan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hesham Misbah', age: 26, country: 'Egypt', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Elnur M?mm?dli', age: 20, country: 'Azerbaijan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Naidangiin Tüvshinbayar', age: 24, country: 'Mongolia', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Misato Nakamura', age: 19, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Idalys Ortíz', age: 18, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ludwig Paischer', age: 26, country: 'Austria', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pak Chol-Min', age: 25, country: 'North Korea', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paula Pareto', age: 22, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lucija Polavder', age: 23, country: 'Slovenia', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stéphanie Possamai', age: 28, country: 'France', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ketleyn Quadros', age: 20, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giulia Quintavalle', age: 25, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Teddy Riner', age: 19, country: 'France', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ronda Rousey', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rishod Sobirov', age: 21, country: 'Uzbekistan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ryoko Tamura-Tani', age: 32, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Abdullo Tangriyev', age: 27, country: 'Uzbekistan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ayumi Tanimoto', age: 27, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tong Wen', age: 25, country: 'China', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irakli Tsirekidze', age: 26, country: 'Georgia', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maki Tsukada', age: 26, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Masato Uchishiba', age: 30, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Masae Ueno', age: 29, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wang Gi-Chun', age: 19, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elisabeth Willeboordse', age: 29, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Won Ok-Im', age: 21, country: 'North Korea', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xian Dongmei', age: 32, country: 'China', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Xu Yan', age: 26, country: 'China', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yang Xiuli', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Askhat Zhitkeyev', age: 27, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Noriko Anno', age: 28, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yordanis Arencibia', age: 24, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daima Beltrán', age: 31, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Annett Böhm', age: 24, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yvonne Bönisch', age: 23, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Edith Bosch', age: 24, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Flávio Canto', age: 29, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Choi Min-Ho', age: 23, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tea Donguzashvili', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gao Feng', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Georgi Georgiev', age: 28, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Driulys González', age: 30, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Deborah Gravenstijn', age: 29, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leandro Guilheiro', age: 21, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Claudia Heill', age: 22, country: 'Austria', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ilse Heylen', age: 27, country: 'Belgium', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roman Hontiuk', age: 20, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mark Huizinga', age: 30, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ilias Iliadis', age: 17, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hiroshi Izumi', age: 22, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jang Seong-Ho', age: 26, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Frédérique Jossinet', age: 28, country: 'France', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Jurack', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Khashbaataryn Tsagaanbaatar', age: 20, country: 'Mongolia', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Nest'or Khergiani", age: 29, country: 'Georgia', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jozef Krnác', age: 26, country: 'Slovakia', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kye Sun-Hui', age: 25, country: 'North Korea', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yurisel Laborde', age: 25, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lee Won-Hui', age: 23, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Liu Xia', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yurisleidy Lupetey', age: 23, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Igor Makarov', age: 25, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vitaly Makarov', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julia Matijass', age: 30, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lucia Morico', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tadahiro Nomura', age: 29, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Nosov', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jimmy Pedro', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Indrek Pertelson', age: 33, country: 'Estonia', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Qin Dongya', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Amarilys Savón', age: 30, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sun Fuming', age: 30, country: 'China', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Keiji Suzuki', age: 24, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryoko Tamura-Tani', age: 28, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ayumi Tanimoto', age: 23, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Khasanbi Taov', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tamerlan Tmenov', age: 27, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maki Tsukada', age: 22, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Masato Uchishiba', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Masae Ueno', age: 25, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dennis van der Geest', age: 29, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xian Dongmei', age: 28, country: 'China', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yuki Yokosawa', age: 23, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Arik Ze'evi", age: 27, country: 'Israel', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Urška Žolnir', age: 22, country: 'Slovenia', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zurab Zviadauri', age: 23, country: 'Georgia', year: 2004, date: '29/08/2004', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daima Beltrán', age: 28, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Larbi Ben Boudaoud', age: 26, country: 'France', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lyubov Bruletova', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksei Budõlin', age: 24, country: 'Estonia', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tiago Camilo', age: 18, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nuno Delgado', age: 24, country: 'Portugal', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Frédéric Demontfaucon', age: 26, country: 'France', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Douillet', age: 31, country: 'France', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Isabel Fernández', age: 28, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicolas Gill', age: 28, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Girolamo Giovinazzo', age: 32, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Driulys González', age: 26, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anna-Maria Gradante', age: 23, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carlos Honorato', age: 25, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kate Howey', age: 27, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mark Huizinga', age: 27, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kosei Inoue', age: 22, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeong Seok-Gyeong', age: 22, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jeong Seong-Suk', age: 28, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jo In-Cheol', age: 24, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jo Min-Seon', age: 28, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Seon-Yeong', age: 21, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kie Kusakabe', age: 21, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kye Sun-Hui', age: 21, country: 'North Korea', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anatoly Laryukov', age: 29, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Céline Lebrun', age: 24, country: 'France', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Li Shufang', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liu Yuxiang', age: 24, country: 'China', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giuseppe Maddaloni', age: 24, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ruslan Mashurenko', age: 29, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tadahiro Nomura', age: 25, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hüseyin Özkan', age: 28, country: 'Turkey', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mária Pekli', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Indrek Pertelson', age: 29, country: 'Estonia', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emanuela Pierantozzi', age: 32, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Manolo Poulot', age: 26, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simona Richter', age: 28, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ylenia Scapin', age: 25, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shinichi Shinohara', age: 27, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ann Simons', age: 20, country: 'Belgium', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aydyn Smagulov', age: 23, country: 'Kyrgyzstan', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yury Styopkin', age: 28, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Noriko Sugawara-Narazaki', age: 27, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Makoto Takimoto', age: 25, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryoko Tamura-Tani', age: 25, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tang Lin', age: 24, country: 'China', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamerlan Tmenov', age: 23, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stéphane Traineau', age: 34, country: 'France', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gella Vandecaveye', age: 27, country: 'Belgium', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Séverine Vandenhende', age: 26, country: 'France', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Georgios Vazagkasvili', age: 26, country: 'Georgia', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sibelis Veranes', age: 26, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Legna Verdecia', age: 27, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mayumi Yamashita', age: 24, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuan Hua', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vsevolods Zelonijs', age: 27, country: 'Latvia', year: 2000, date: '01/10/2000', sport: 'Judo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Meghan Agosta', age: 23, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gillian Apps', age: 26, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Backes', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Niklas Bäckström', age: 32, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kacey Bellamy', age: 22, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Patrice Bergeron-Cleary', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tessa Bonhomme', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jennifer Botterill', age: 30, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dan Boyle', age: 33, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Martin Brodeur', age: 37, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dustin Brown', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Caitlin Cahow', age: 24, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ryan Callahan', age: 24, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lisa Chesson', age: 23, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julie Chu', age: 27, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sidney Crosby', age: 22, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Natalie Darwitz', age: 26, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Drew Doughty', age: 20, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Drury', age: 33, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Meghan Duggan', age: 22, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Molly Engstrom', age: 26, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valtteri Filppula', age: 25, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ryan Getzlaf', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tim Gleason', age: 27, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Niklas Hagman', age: 30, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dany Heatley', age: 29, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jayna Hefford', age: 32, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anne Helin', age: 23, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jenni Hiirikoski', age: 22, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Venla Hovi', age: 22, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jarome Iginla', age: 32, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jarkko Immonen', age: 27, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Haley Irwin', age: 21, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erik Johnson', age: 21, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jack Johnson', age: 23, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rebecca Johnston', age: 20, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olli Jokinen', age: 31, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Patrick Kane', age: 21, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Niko Kapanen', age: 31, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michelle Karvinen', age: 19, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Duncan Keith', age: 26, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Becky Kellar', age: 35, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryan Kesler', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Phil Kessel', age: 22, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gina Kingsbury', age: 28, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Miikka Kiprusoff', age: 33, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hilary Knight', age: 20, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mikko Koivu', age: 26, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Saku Koivu', age: 35, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lasse Kukkonen', age: 28, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emma Laaksonen', age: 28, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Charlie Labonté', age: 27, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jocelyne Lamoureux', age: 20, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Monique Lamoureux', age: 20, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jamie Langenbrunner', age: 34, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Erika Lawler', age: 23, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jere Lehtinen', age: 36, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sami Lepistö', age: 25, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rosa Lindstedt', age: 22, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roberto Luongo', age: 30, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Toni Lydman', age: 32, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carla MacLeod', age: 27, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryan Malone', age: 30, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Patrick Marleau', age: 30, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gigi Marvin', age: 22, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brianne McLaughlin', age: 22, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Terhi Mertanen', age: 28, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Antti Miettinen', age: 29, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Meaghan Mikkelson', age: 25, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryan Miller', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brenden Morrow', age: 31, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rick Nash', age: 25, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Scott Niedermayer', age: 36, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Janne Niskala', age: 28, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brooks Orpik', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Caroline Ouellette', age: 30, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zach Parise', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joe Pavelski', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ville Peltonen', age: 36, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Heidi Pelttari', age: 24, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Corey Perry', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cherie Piper', age: 28, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Joni Pitkänen', age: 26, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mariia Posa', age: 21, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marie-Philip Poulin', age: 18, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Pronger', age: 35, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brian Rafalski', age: 36, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Annina Rajahuhta', age: 20, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karoliina Rantamäki', age: 31, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Noora Räty', age: 20, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mike Richards', age: 25, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Angela Ruggiero', age: 30, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jarkko Ruutu', age: 34, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tuomo Ruutu', age: 27, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bobby Ryan', age: 22, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mari Saarinen', age: 28, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sami Salo', age: 35, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Molly Schaus', age: 21, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jenny Schmidgall-Potter', age: 31, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brent Seabrook', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Teemu Selänne', age: 39, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Saija Sirviö', age: 27, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Colleen Sostorics', age: 30, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim St-Pierre', age: 31, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eric Staal', age: 25, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kelli Stack', age: 22, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paul Stastny', age: 24, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ryan Suter', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shannon Szabados', age: 23, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karen Thatcher', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tim Thomas', age: 35, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joe Thornton', age: 30, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nina Tikkinen', age: 23, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kimmo Timonen', age: 34, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jonathan Toews', age: 21, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Minnamari Tuominen', age: 19, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Saara Tuominen', age: 24, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sarah Vaillancourt', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Linda Välimäki', age: 19, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jessie Vetter', age: 24, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marjo Voutilainen', age: 28, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Catherine Ward', age: 22, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shea Weber', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kerry Weiland', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ryan Whitney', age: 26, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hayley Wickenheiser', age: 31, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jinelle Zaugg-Siergiej', age: 23, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Meghan Agosta', age: 18, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniel Alfredsson', age: 33, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cecilia Andersson', age: 23, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gunilla Andersson', age: 30, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gillian Apps', age: 22, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jenni Asserholt', age: 17, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Per-Johan Axelsson', age: 30, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christian Bäckman', age: 25, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aki Berg', age: 28, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jennifer Botterill', age: 26, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jan Bulis', age: 27, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Caitlin Cahow', age: 20, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Petr Cajánek', age: 30, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cassie Campbell', age: 32, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Julie Chu', age: 23, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Natalie Darwitz', age: 22, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pam Dreyer', age: 24, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tricia Dunn-Luoma', age: 31, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ann-Louise Edstrand', age: 30, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joa Elfsberg', age: 26, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Patrik Eliáš', age: 29, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emma Eliasson', age: 16, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Molly Engstrom', age: 22, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martin Erat', age: 24, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gillian Ferrari', age: 25, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Forsberg', age: 32, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Danielle Goyette', age: 40, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chanda Gunn', age: 26, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jamie Hagerman', age: 24, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Niklas Hagman', age: 26, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mika Hannula', age: 26, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dominik Hašek', age: 41, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Niclas Hävelid', age: 32, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jayna Hefford', age: 28, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Milan Hejduk', age: 30, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleš Hemský', age: 22, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jukka Hentunen', age: 31, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Milan Hnilicka', age: 32, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tomas Holmström', age: 33, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erika Holst', age: 26, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Insalaco', age: 25, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jaromír Jágr', age: 34, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nanna Jansson', age: 22, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jussi Jokinen', age: 22, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olli Jokinen', age: 27, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jörgen Jönsson', age: 33, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kenny Jönsson', age: 31, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'František Kaberle', age: 32, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tomáš Kaberle', age: 27, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Niko Kapanen', age: 27, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kathleen Kauth', age: 26, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Becky Kellar', age: 31, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Courtney Kennedy', age: 26, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Katie King', age: 30, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kristin King', age: 26, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gina Kingsbury', age: 24, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mikko Koivu', age: 22, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Saku Koivu', age: 31, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleš Kotalík', age: 27, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Niklas Kronwall', age: 25, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Filip Kuba', age: 29, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pavel Kubina', age: 28, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lasse Kukkonen', age: 24, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Antti Laaksonen', age: 32, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Charlie Labonté', age: 23, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Robert Lang', age: 35, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jere Lehtinen', age: 32, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicklas Lidström', age: 35, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ylva Lindberg', age: 29, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jenny Lindqvist', age: 27, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stefan Liv', age: 25, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristina Lundberg', age: 20, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Henrik Lundqvist', age: 23, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Toni Lydman', age: 28, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carla MacLeod', age: 23, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marek Malík', age: 30, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Martin', age: 19, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fredrik Modin', age: 31, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Frida Nevalainen', age: 19, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Antti-Jussi Niemi', age: 28, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ville Nieminen', age: 28, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Antero Niittymäki', age: 25, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fredrik Norrena', age: 32, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Petteri Nummelin', age: 33, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Teppo Numminen', age: 37, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Emilie O'Konor", age: 22, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mattias Öhlund', age: 29, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rostislav Olesz', age: 20, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Caroline Ouellette', age: 26, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Samuel Påhlsson', age: 28, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Parsons', age: 18, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ville Peltonen', age: 32, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cherie Piper', age: 24, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cheryl Pounder', age: 29, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Václav Prospal', age: 30, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Helen Resor', age: 20, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maria Rooth', age: 26, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martin Rucinský', age: 34, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Angela Ruggiero', age: 26, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Danijela Rundqvist', age: 21, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jarkko Ruutu', age: 30, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sami Salo', age: 31, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mikael Samuelsson', age: 29, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jenny Schmidgall-Potter', age: 27, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniel Sedin', age: 25, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Henrik Sedin', age: 25, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Teemu Selänne', age: 35, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Therese Sjölander', age: 24, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Colleen Sostorics', age: 26, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jaroslav Špacek', age: 32, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim St-Pierre', age: 27, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kelly Stephens', age: 22, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martin Straka', age: 33, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mats Sundin', age: 35, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ronnie Sundin', age: 35, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vicky Sunohara', age: 35, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mikael Tellqvist', age: 26, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katarina Timglas', age: 20, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kimmo Timonen', age: 30, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniel Tjärnqvist', age: 29, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Vaillancourt', age: 20, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Vikman', age: 25, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tomáš Vokoun', age: 29, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Výborný', age: 31, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lyndsay Wall', age: 20, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Katie Weatherston', age: 22, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Krissy Wendell', age: 24, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hayley Wickenheiser', age: 27, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pernilla Winberg', age: 16, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Henrik Zetterberg', age: 25, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marek Židlický', age: 29, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maksim Afinogenov', age: 22, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Annica Åhlén', age: 27, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lotta Almblad', age: 29, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tony Amonte', age: 31, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anna Andersson', age: 20, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gunilla Andersson', age: 26, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dana Antal', age: 24, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Bailey', age: 30, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laurie Baker', age: 25, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tom Barrasso', age: 36, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kelly Béchard', age: 24, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emelie Berggren', age: 19, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kristina Bergstrand', age: 38, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rob Blake', age: 32, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jennifer Botterill', age: 22, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eric Brewer', age: 22, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thérèse Brisson', age: 35, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Martin Brodeur', age: 29, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pavel Bure', age: 30, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Valery Bure', age: 27, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karyn Bye', age: 30, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cassie Campbell', age: 28, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Isabelle Chartrand', age: 23, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Chelios', age: 40, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julie Chu', age: 19, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Natalie Darwitz', age: 18, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pavel Datsyuk', age: 23, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adam Deadmarsh', age: 26, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sara DeCosta', age: 24, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chris Drury', age: 25, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mike Dunham', age: 29, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tricia Dunn-Luoma', age: 27, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lori Dupuis', age: 29, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ann-Louise Edstrand', age: 26, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joa Elfsberg', age: 22, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Theo Fleury', age: 33, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adam Foote', age: 30, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sergey Fyodorov', age: 32, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simon Gagné', age: 21, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sergey Gonchar', age: 27, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Danielle Goyette', age: 36, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cammi Granato', age: 30, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bill Guerin', age: 31, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Geraldine Heaney', age: 34, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jayna Hefford', age: 24, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erika Holst', age: 22, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Phil Housley', age: 37, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brett Hull', age: 37, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jarome Iginla', age: 24, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nanna Jansson', age: 18, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Curtis Joseph', age: 34, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ed Jovanovski', age: 25, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paul Kariya', age: 27, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Darius Kasparaitis', age: 29, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Becky Kellar', age: 27, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Courtney Kennedy', age: 22, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikolay Khabibulin', age: 29, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrea Kilbourne', age: 21, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katie King', age: 26, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ilya Kovalchuk', age: 18, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Kovalyov', age: 28, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Igor Kravchuk', age: 35, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oleg Kvasha', age: 23, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Igor Larionov', age: 41, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maria Larsson', age: 22, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'John LeClair', age: 32, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brian Leetch', age: 33, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mario Lemieux', age: 36, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ylva Lindberg', age: 25, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eric Lindros', age: 28, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ulrica Lindström', age: 22, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shelley Looney', age: 30, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Al MacInnis', age: 38, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vladimir Malakhov', age: 33, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Danny Markov', age: 25, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Martin', age: 15, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sue Merz', age: 29, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aaron Miller', age: 30, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Boris Mironov', age: 29, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'A. J. Mleczko', age: 26, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mike Modano', age: 31, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tara Mounsey', age: 23, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Scott Niedermayer', age: 28, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Joe Nieuwendyk', age: 35, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Nikolishin', age: 28, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Owen Nolan', age: 29, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Caroline Ouellette', age: 22, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mike Peca', age: 27, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Josefin Pettersson', age: 18, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cherie Piper', age: 20, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tom Poti', age: 24, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cheryl Pounder', age: 25, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Pronger', age: 27, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brian Rafalski', age: 28, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mike Richter', age: 35, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jeremy Roenick', age: 32, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brian Rolston', age: 28, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maria Rooth', age: 22, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Angela Ruggiero', age: 22, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Danijela Rundqvist', age: 17, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joe Sakic', age: 32, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sergey Samsonov', age: 23, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Evelina Samuelsson', age: 17, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jenny Schmidgall-Potter', age: 23, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brendan Shanahan', age: 33, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tammy Lee Shewchuk', age: 24, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Therese Sjölander', age: 20, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sami Jo Small', age: 25, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryan Smyth', age: 25, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Colleen Sostorics', age: 22, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim St-Pierre', age: 23, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vicky Sunohara', age: 31, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gary Suter', age: 37, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Keith Tkachuk', age: 29, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sarah Tueting', age: 25, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oleg Tverdovsky', age: 25, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Vikman', age: 21, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lyndsay Wall', age: 16, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Doug Weight', age: 31, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Krissy Wendell', age: 20, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hayley Wickenheiser', age: 23, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Yashin', age: 28, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mike York', age: 24, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Scott Young', age: 34, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steve Yzerman', age: 36, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Zhamnov', age: 31, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Ice Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: '', age: 32, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: '', age: 34, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marilyn Agliotti', age: 33, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lucha Aymar', age: 34, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sander Baart', age: 24, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Billy Bakker', age: 23, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marcel Balkestein', age: 31, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ashleigh Ball', age: 26, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Noel Barrionuevo', age: 28, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laura Bartlett', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nathan Burgers', age: 33, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matthew Butturini', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joel Carroll', age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martina Cavallero', age: 22, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chris Ciriello', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Crista Cullen', age: 26, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Silvina D'Elia", age: 26, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alex Danson', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Merel de Blaey', age: 25, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eva de Goede', age: 23, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Teun de Nooijer', age: 36, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bob de Voogd', age: 23, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sander de Wijn', age: 22, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liam De Young', age: 30, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Timothy Deavin', age: 28, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oskar Deecke', age: 26, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carlien Dirkse van den Heuvel', age: 25, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jamie Dwyer', age: 33, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Floris Evers', age: 29, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Russell Ford', age: 28, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Florian Fuchs', age: 20, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Moritz Fürste', age: 27, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maartje Goderie', age: 28, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt Gohdes', age: 22, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kieran Govers', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Florencia Habif', age: 18, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martin Häner', age: 23, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tobias Hauke', age: 24, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rogier Hofman', age: 25, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ellen Hoog', age: 26, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tim Jenniskens', age: 25, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wouter Jolie', age: 27, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kelly Jonker', age: 22, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fergus Kavanagh', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robbert Kemperman', age: 22, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mark Knowles', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oliver Korn', age: 28, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Lammers', age: 31, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rosario Luchetti', age: 28, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sofia Maccari', age: 28, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hannah Macleod', age: 28, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emily Maguire', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Delfina Merino', age: 22, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Max Müller', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'María Mutio', age: 27, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eddie Ockenden', age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simon Orchard', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ann Panter', age: 28, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maartje Paumen', age: 26, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sophie Polkamp', age: 27, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jan Philipp Rabente', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carla Rebecchi', age: 27, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Helen Richardson', age: 30, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ana Rodríguez', age: 31, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chloe Rogers', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rocio Sánchez', age: 23, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maru Scarone', age: 25, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joyce Sombroek', age: 21, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dani Sruoga', age: 24, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jose Sruoga', age: 21, country: 'Argentina', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jaap Stockmann', age: 28, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Beth Storry', age: 34, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thilo Stralkowski', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matthew Swann', age: 23, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sarah Thomas', age: 31, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Glenn Turner', age: 28, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Georgie Twigg', age: 21, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura Unsworth', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Naomi van As', age: 29, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Robert van der Horst', age: 27, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mink van der Weerden', age: 23, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Margot van Geffen', age: 22, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Caia van Maasakker', age: 23, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kitty van Male', age: 24, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Valentin Verga', age: 22, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Klaas Vermeulen', age: 24, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kate Walsh', age: 32, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sally Walton', age: 31, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Max Weinhold', age: 30, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lidewij Welten', age: 22, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christopher Wesley', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roderick Weusthof', age: 30, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Benjamin Weß', age: 27, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Timo Weß', age: 30, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicola White', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matthias Witthaus', age: 30, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christopher Zeller', age: 27, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Philipp Zeller', age: 29, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Des Abbott', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marilyn Agliotti', age: 29, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Magdalena Aicega', age: 34, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Alegre', age: 23, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ramón Alegre', age: 27, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pol Amat', age: 30, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eduard Arbós', age: 25, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lucha Aymar', age: 31, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Noel Barrionuevo', age: 24, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sebastian Biederlack', age: 26, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Minke Booij', age: 31, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Travis Brooks', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kiel Brown', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Claudia Burkart', age: 28, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chen Qiuqi', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chen Zhaoxia', age: 33, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cheng Hui', age: 35, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Quico Cortés', age: 25, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eva de Goede', age: 19, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lisanne de Roever', age: 29, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Liam De Young', age: 26, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wieke Dijkstra', age: 24, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luke Doerner', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jamie Dwyer', age: 29, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergi Enrique', age: 20, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alex Fábregas', age: 27, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kiko Fábregas', age: 30, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juan Fernández', age: 23, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Santi Freixa', age: 25, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fu Baorong', age: 30, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Moritz Fürste', age: 23, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gao Lihua', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sole García', age: 27, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rodrigo Garza', age: 28, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bevan George', age: 31, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maartje Goderie', age: 24, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariana González', age: 32, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Guest', age: 26, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alejandra Gulla', age: 31, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rob Hammond', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tobias Hauke', age: 20, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maripi Hernández', age: 31, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ellen Hoog', age: 22, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Huang Junxia', age: 32, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gisi Kañevsky', age: 23, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fergus Kavanagh', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Florian Keller', age: 26, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Knowles', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oliver Korn', age: 24, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stephen Lambert', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Hongxia', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Li Shuang', age: 30, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rosario Luchetti', age: 24, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ma Yibo', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mechi Margalot', age: 33, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eli Matheson', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Niklas Meinert', age: 27, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jan-Marco Montag', age: 24, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fátima Moreira de Melo', age: 30, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eefke Mulder', age: 30, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Max Müller', age: 21, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carlos Nevado', age: 25, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eddie Ockenden', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roc Oliva', age: 19, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pan Fengzhen', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maartje Paumen', age: 22, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sophie Polkamp', age: 24, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carla Rebecchi', age: 23, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ren Ye', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Xavier Ribas', age: 32, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariana Rossi', age: 29, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mariné Russo', age: 28, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Albert Sala', age: 27, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Janneke Schopman', age: 31, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Grant Schubert', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Minke Smabers', age: 29, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrew Smith', age: 29, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Víctor Sojo', age: 24, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Song Qingling', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Belén Succi', age: 22, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tang Chunling', age: 32, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eddie Tubau', age: 27, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Naomi van As', age: 25, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Miek van Geenhuizen', age: 26, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paola Vukojicic', age: 33, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Max Weinhold', age: 26, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tibor Weißenborn', age: 27, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt Wells', age: 30, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lidewij Welten', age: 18, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Benjamin Weß', age: 23, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Timo Weß', age: 26, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Philip Witte', age: 24, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matthias Witthaus', age: 26, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christopher Zeller', age: 23, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Philipp Zeller', age: 25, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Yimeng', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhao Yudiao', age: 19, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhou Wanfeng', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Magdalena Aicega', age: 30, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mariela Antoniska', age: 29, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Clemens Arnold', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Inés Arrondo', age: 26, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lucha Aymar', age: 27, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tina Bachmann', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christoph Bechmann', age: 32, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sebastian Biederlack', age: 22, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Minke Booij', age: 27, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ageeth Boomgaardt', age: 31, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Brennan', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Travis Brooks', age: 24, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matthijs Brouwer', age: 24, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ronald Brouwer', age: 25, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Claudia Burkart', age: 24, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dean Butler', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Caroline Casaretto', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Philipp Crone', age: 27, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chantal de Bruijn', age: 28, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Teun de Nooijer', age: 28, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lisanne de Roever', age: 25, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liam De Young', age: 22, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeroen Delmeé', age: 31, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Geert-Jan Derikx', age: 23, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rob Derikx', age: 21, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marina Di Giacomo', age: 28, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mijntje Donners', age: 30, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eike Duckwitz', age: 24, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jamie Dwyer', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nathan Eglington', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marten Eikelboom', age: 30, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christoph Eimer', age: 27, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Troy Elder', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Björn Emmerling', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nadine Ernsting-Krienke', age: 30, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Floris Evers', age: 21, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sole García', age: 23, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bevan George', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariana González', age: 28, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Franziska Gude', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alejandra Gulla', age: 27, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mandy Haase', age: 22, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rob Hammond', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maripi Hernández', age: 27, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mark Hickman', age: 30, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erik Jazet', age: 33, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sylvia Karres', age: 27, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Natascha Keller', age: 27, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karel Klaver', age: 25, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Denise Klecker', age: 32, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Knowles', age: 19, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anke Kühn', age: 23, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Florian Kunz', age: 32, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Badri Latif', age: 27, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Heike Lätzsch', age: 30, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sonja Lehmann', age: 24, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brent Livermore', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jesse Mahieu', age: 26, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mechi Margalot', age: 29, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michael McCann', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Björn Michel', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fátima Moreira de Melo', age: 26, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stephen Mowlam', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eefke Mulder', age: 26, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Silke Müller', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vanina Oneto', age: 31, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rob Reckers', age: 22, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sascha Reinelt', age: 31, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fanny Rinne', age: 24, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marion Rodewald', age: 27, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ceci Rognoni', age: 27, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mariné Russo', age: 24, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Justus Scharowsky', age: 24, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maartje Scheepstra', age: 24, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Janneke Schopman', age: 27, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Grant Schubert', age: 24, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christian Schulte', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Clarinda Sinnige', age: 31, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Minke Smabers', age: 25, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jiske Snoeks', age: 26, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ayelén Stepnik', age: 28, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Taeke Taekema', age: 24, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Macha van der Vaart', age: 32, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sander van der Weide', age: 28, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Miek van Geenhuizen', age: 22, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lieve van Kessel', age: 26, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Klaas Veering', age: 22, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Guus Vogels', age: 29, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paola Vukojicic', age: 29, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Louisa Walter', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tibor Weißenborn', age: 23, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matt Wells', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Timo Weß', age: 22, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matthias Witthaus', age: 22, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christopher Zeller', age: 19, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Julia Zwehl', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Magdalena Aicega', age: 26, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katie Allen', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alyson Annan', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariela Antoniska', age: 25, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Inés Arrondo', age: 22, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lucha Aymar', age: 23, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Minke Booij', age: 23, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ageeth Boomgaardt', age: 27, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michael Brennan', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jacques Brinkman', age: 34, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jaap-Derk Buma', age: 28, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adam Commens', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stephen Davies', age: 31, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Teun de Nooijer', age: 24, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Julie Deiters', age: 25, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeroen Delmeé', age: 27, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Damon Diletti', age: 29, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mijntje Donners', age: 26, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lachlan Dreher', age: 33, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jason Duff', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marten Eikelboom', age: 26, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Troy Elder', age: 22, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jimmy Elmer', age: 29, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Renita Farrell-Garard', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'María Paz Ferrari', age: 27, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anabel Gambero', age: 28, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gang Geon-Uk', age: 29, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sole García', age: 19, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paul Gaudoin', age: 25, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Piet-Hein Geeris', age: 28, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Han Hyeong-Bae', age: 24, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juliet Haslam', age: 31, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rechelle Hawkes', age: 33, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maripi Hernández', age: 23, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stephen Holt', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikki Hudson', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hwang Jong-Hyeon', age: 25, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Im Jeong-U', age: 22, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Im Jong-Cheon', age: 22, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rachel Imison', age: 21, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ronald Jansen', age: 36, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erik Jazet', age: 29, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeon Jong-Gwon', age: 21, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jeon Jong-Ha', age: 27, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ji Seong-Hwan', age: 26, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Cheong-Hwan', age: 29, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Gyeong-Seok', age: 28, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Jeong-Cheol', age: 23, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Yong-Bae', age: 26, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Yun', age: 26, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brent Livermore', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bram Lomans', age: 25, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Clover Maitland', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Laura Maiztegui', age: 21, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mechi Margalot', age: 25, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Karina Masotta', age: 29, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Claire Mitchell-Taverner', age: 30, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fátima Moreira de Melo', age: 22, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jenny Morris', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vanina Oneto', age: 27, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alison Peek', age: 30, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Triny Powell', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lisa Powell-Carruthers', age: 30, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jorgelina Rimoldi', age: 28, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ceci Rognoni', age: 23, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Seo Jong-Ho', age: 20, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Clarinda Sinnige', age: 27, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Angie Skirving-Lambert', age: 19, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hanneke Smabers', age: 26, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Minke Smabers', age: 21, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Song Seong-Tae', age: 28, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniel Sproule', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jay Stacy', age: 32, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kate Starre', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ayelén Stepnik', age: 24, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Margje Teeuwen', age: 26, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carole Thate', age: 28, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daphne Touw', age: 30, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Julie Towers', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fleur van de Kieft', age: 26, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dillianne van den Boogaard', age: 26, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Macha van der Vaart', age: 28, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sander van der Weide', age: 24, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Suzan van der Wielen', age: 28, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wouter van Pelt', age: 32, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diederik van Weel', age: 26, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Remco van Wijk', age: 27, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stephan Veen', age: 30, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Myrna Veenstra', age: 25, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Craig Victory', age: 20, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Guus Vogels', age: 25, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paola Vukojicic', age: 26, country: 'Argentina', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Matt Wells', age: 22, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peter Wind', age: 27, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yeo Wun-Gon', age: 26, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael York', age: 32, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Hockey', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Luc Abalo', age: 27, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'William Accambray', age: 24, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Macarena Aguilar', age: 27, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nely Alberto', age: 29, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mirko Alilovic', age: 26, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jessica Alonso', age: 28, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ida Alstad', age: 27, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vanessa Amorós', age: 29, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Andersson', age: 29, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mattias Andersson', age: 34, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ivano Balic', age: 33, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xavier Barachet', age: 23, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sonja Barjaktarovic', age: 25, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrea Barno', age: 32, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Damir Bicanic', age: 27, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karoline Dyhre Breivang', age: 32, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andela Bulatovic', age: 25, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katarina Bulatovic', age: 27, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Denis Buntic', age: 29, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mihaela Ciobanu', age: 39, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Verónica Cuadrado', age: 33, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ivan Cupic', age: 26, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Didier Dinart', age: 35, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dalibor Doder', age: 33, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Domagoj Duvnjak', age: 24, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Niclas Ekberg', age: 23, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Ekdahl du Rietz', age: 23, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Patricia Elorza', age: 28, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Beatriz Fernández', age: 27, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Begoña Fernández', age: 32, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jérôme Fernandez', age: 35, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marit Malm Frafjord', age: 26, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bertrand Gille', age: 34, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Guillaume Gille', age: 36, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jakov Gojun', age: 26, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kari Aalvik Grimsbø', age: 27, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michaël Guigou', age: 30, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mattias Gustafsson', age: 34, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katrine Lunde Haraldsen', age: 32, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Camilla Herrem', age: 25, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Samuel Honrubia', age: 26, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zlatko Horvat', age: 27, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Johan Jakobsson', age: 25, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Magnus Jernemyr', age: 36, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kari Mette Johansen', age: 33, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Guillaume Joli', age: 27, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marija Jovanovic', age: 26, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jonas Källman', age: 31, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikola Karabatic', age: 28, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daouda Karaboué', age: 36, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tobias Karlsson', age: 31, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Milena Kneževic', age: 22, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marko Kopljar', age: 26, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Amanda Kurtovic', age: 21, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Blaženko Lackovic', age: 31, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jonas Larholm', age: 30, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Suzana Lazovic', age: 20, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marta López', age: 22, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Venio Losert', age: 36, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kristine Lunde-Borgersen', age: 32, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Heidi Løke', age: 29, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marta Mangué', age: 29, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carmen Martín', age: 24, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Majda Mehmedovic', age: 22, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Radmila Miljanic', age: 24, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniel Narcisse', age: 32, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Silvia Navarro', age: 33, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreas Nilsson', age: 22, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ivan Nincevic', age: 30, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tonje Nøstvold', age: 27, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thierry Omeyer', age: 35, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fredrik Petersen', age: 28, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eli Pinedo', age: 31, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bojana Popovic', age: 32, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jova Radicevic', age: 25, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ana Radovic', age: 25, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Linn-Kristin Riegelhuth Koren', age: 27, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maja Savic', age: 36, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Johan Sjöstrand', age: 25, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gøril Snorroeggen', age: 27, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cédric Sorhaindo', age: 28, country: 'France', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Manuel Štrlek', age: 23, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Linn Jørum Sulland', age: 28, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Igor Vori', age: 31, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marina Vukcevic', age: 18, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Drago Vukovic', age: 28, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ana Ðokic', age: 33, country: 'Montenegro', year: 2012, date: '12/08/2012', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ragnhild Aamodt', age: 27, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luc Abalo', age: 23, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Joël Abati', age: 37, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'An Jeong-Hwa', age: 27, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yekaterina Andryushina', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sturla Ásgeirsson', age: 28, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Arnór Atlason', age: 24, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bae Min-Hee', age: 20, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Barrufet', age: 38, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jon Belaustegui', age: 29, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Inna Bliznova', age: 21, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Karoline Dyhre Breivang', age: 28, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cédric Burdet', age: 33, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Choi Im-Jeong', age: 27, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Davis', age: 31, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Didier Dinart', age: 31, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yelena Dmitriyeva', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alberto Entrerríos', age: 31, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Raúl Entrerríos', age: 27, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jérôme Fernandez', age: 31, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marit Malm Frafjord', age: 22, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rubén Garabaya', age: 29, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Juan García', age: 30, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Logi Geirsson', age: 25, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bertrand Gille', age: 30, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Guillaume Gille', age: 32, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olivier Girault', age: 35, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kari Aalvik Grimsbø', age: 23, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michaël Guigou', age: 26, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Róbert Gunnarsson', age: 28, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Björgvin Gustavsson', age: 23, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Snorri Guðjónsson', age: 26, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hreiðar Guðmundsson', age: 27, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ásgeir Örn Hallgrímsson', age: 24, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gro Hammerseng', age: 28, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katrine Lunde Haraldsen', age: 28, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Heo Sun-Yeong', age: 32, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'José Javier Hombrados', age: 36, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hong Jeong-Ho', age: 34, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ingimundur Ingimundarson', age: 28, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sverre Jakobsson', age: 31, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kari Mette Johansen', age: 29, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nikola Karabatic', age: 24, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daouda Karaboué', age: 32, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Kareyeva', age: 31, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christophe Kempé', age: 33, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Cha-Yeon', age: 27, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Nam-Sun', age: 27, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim On-A', age: 19, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tonje Larsen', age: 33, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lee Min-Hui', age: 28, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Demetrio Lozano', age: 32, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kristine Lunde-Borgersen', age: 28, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cristian Malmagro', age: 25, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yekaterina Marennikova', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mun Pil-Hui', age: 25, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniel Narcisse', age: 28, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katja Nyberg', age: 28, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tonje Nøstvold', age: 23, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Oh Seong-Ok', age: 35, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oh Yeong-Ran', age: 35, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thierry Omeyer', age: 31, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Park Jeong-Hui', age: 33, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cédric Paty', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alexander Petersson', age: 28, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Irina Poltoratskaya', age: 29, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Polyonova', age: 24, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lyudmila Postnova', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carlos Prieto', age: 28, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Linn-Kristin Riegelhuth Koren', age: 24, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Albert Rocas', age: 26, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oksana Romenskaya', age: 32, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iker Romero', age: 28, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Shipilova', age: 28, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Sidorova', age: 28, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Guðjón Valur Sigurðsson', age: 29, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sigfús Sigurðsson', age: 33, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gøril Snorroeggen', age: 23, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Song Hai-Rim', age: 23, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ólafur Stefánsson', age: 35, country: 'Iceland', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Inna Suslina', age: 29, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Else-Marthe Sørlie Lybekk', age: 29, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Víctor Tomás', age: 23, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emiliya Turey', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yana Uskova', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kristine Andersen', age: 28, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ivano Balic', age: 25, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Markus Baur', age: 33, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anastasiya Borodina', age: 22, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Borysenko', age: 28, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karen Brødsgaard', age: 26, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hanna Burmistrova', age: 27, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mikhail Chipurin', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Choi Im-Jeong', age: 23, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Line Daugaard', age: 26, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Davor Dominikovic', age: 26, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Dragunski', age: 33, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mirza Džomba', age: 27, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Henning Fritz', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katrine Fruelund', age: 26, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Slavko Goluža', age: 32, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Gorbatikov', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vyacheslav Gorpishin', age: 34, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pascal Hens', age: 24, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heo Sun-Yeong', age: 28, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heo Yeong-Suk', age: 29, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iryna Honcharova', age: 29, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rikke Hørlykke', age: 28, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Im O-Gyeong', age: 32, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jan-Olaf Immel', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vitaly Ivanov', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jang So-Hui', age: 26, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Torsten Jansen', age: 27, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Trine Jensen', age: 23, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nikša Kaleb', age: 31, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Florian Kehrmann', age: 27, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Cha-Yeon', age: 23, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Hyeon-Ok', age: 30, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lotte Kiærskou', age: 29, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eduard Koksharov', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Kostygov', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stefan Kretzschmar', age: 31, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Denis Krivoshlykov', age: 33, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vasily Kudinov', age: 35, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oleg Kuleshov', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Blaženko Lackovic', age: 23, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Lavrov', age: 42, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lee Gong-Ju', age: 24, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Sang-Eun', age: 29, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nataliya Liapina', age: 28, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Venio Losert', age: 28, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Halyna Markushevska', age: 28, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Valter Matoševic', age: 34, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Petar Metlicic', age: 27, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Henriette Mikkelsen', age: 23, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karin Mortensen', age: 26, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mun Gyeong-Ha', age: 24, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mun Pil-Hui', age: 21, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Myeom Bok-Hui', age: 25, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Louise Bager Nørgaard', age: 22, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Oh Seong-Ok', age: 31, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oh Yeong-Ran', age: 31, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Klaus-Dieter Petersen', age: 35, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rikke Petersen-Schmidt', age: 29, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sergey Pogorelov', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olena Radchenko', age: 31, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oksana Raikhel', age: 27, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christian Ramota', age: 31, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Rastvortsev', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christian Schwarzer', age: 34, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liudmyla Shevchenko', age: 34, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tetiana Shynkarenko', age: 25, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hanna Siukalo', age: 27, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rikke Skov', age: 23, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vlado Šola', age: 35, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Denis Špoljaric', age: 24, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Goran Šprem', age: 25, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniel Stephan', age: 31, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Camilla Thomsen', age: 29, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Torgovanov', age: 32, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Josephine Touray', age: 24, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olena Tsyhytsia', age: 29, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Tuchkin', age: 40, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maryna Verheliuk', age: 26, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mette Vestergaard', age: 28, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Frank von Behren', age: 27, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Igor Vori', age: 23, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Drago Vukovic', age: 21, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wu Seon-Hui', age: 26, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olena Yatsenko', age: 26, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Larysa Zaspa', age: 32, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christian Zeitz', age: 23, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Volker Zerbe', age: 36, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vedran Zrnic', age: 24, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Camilla Andersen', age: 27, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Magnus Andersson', age: 34, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Beatrix Balogh', age: 25, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'David Barrufet', age: 30, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martin Boquist', age: 23, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Karen Brødsgaard', age: 22, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tina Bøttzau', age: 29, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rita Deli', age: 28, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kristine Duvholt', age: 26, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Talant Duyshebayev', age: 32, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ann-Cathrin Eriksen', age: 29, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ágnes Farkas', age: 27, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrea Farkas', age: 31, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dmitry Filippov', age: 31, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Martin Frändesjö', age: 29, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mathias Franzén', age: 25, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katrine Fruelund', age: 22, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mateo Garralda', age: 30, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peter Gentzel', age: 31, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Susann Goksør-Bjerkrheim', age: 30, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vyacheslav Gorpishin', age: 30, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kjersti Grini', age: 29, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maja Grønbek', age: 29, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rafael Guijosa', age: 31, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Trine Haltvik', age: 35, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Elisabeth Hilmo', age: 23, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anette Hoffmann-Møberg', age: 29, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mia Hundvin', age: 23, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anikó Kántor', age: 32, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oleg Khodkov', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lotte Kiærskou', age: 25, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tonje Kjærgaard', age: 25, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Beatrix Kökény', age: 31, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eduard Koksharov', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Janne Kolling', age: 32, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Denis Krivoshlykov', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vasily Kudinov', age: 31, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anita Kulcsár', age: 23, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stanislav Kulinchenko', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Kuzelev', age: 30, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tonje Larsen', age: 25, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreas Larsson', age: 26, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrey Lavrov', age: 38, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Igor Lavrov', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cecilie Leganger', age: 25, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ola Lindgren', age: 36, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stefan Lövgren', age: 29, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dóra Lowy', age: 23, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Demetrio Lozano', age: 24, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Enric Massip', age: 31, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karin Mortensen', age: 22, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anikó Nagy', age: 30, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anja Nielsen', age: 25, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeanette Nilsen', age: 28, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jordi Nuñez', age: 31, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Xavier O'Callaghan", age: 28, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Josu Olalla', age: 29, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Staffan Olsson', age: 36, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Antonio Ortega', age: 29, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ildikó Pádár', age: 30, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katalin Pálinger', age: 21, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juan Pérez', age: 26, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rikke Petersen-Schmidt', age: 25, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Johan Pettersson', age: 27, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Pogorelov', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bojana Radulovics', age: 27, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lene Rantala', age: 32, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marianne Rokne', age: 22, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christina Roslyng', age: 22, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Monica Sandve', age: 26, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Krisztina Sepsiné Pigniczki', age: 24, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Judit Simics-Zsemberi', age: 32, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Beáta Siti', age: 26, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tomas Sivertsson', age: 35, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pavel Sukosyan', age: 38, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tomas Svensson', age: 32, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Birgitte Sættem', age: 22, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Else-Marthe Sørlie Lybekk', age: 22, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pierre Thorsson', age: 34, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heidi Tjugum', age: 27, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dmitry Torgovanov', age: 28, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Tuchkin', age: 36, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antonio Ugalde', age: 24, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iñaki Urdangarín', age: 32, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alberto Urdiales', age: 31, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mette Vestergaard', age: 24, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lev Voronin', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ljubomir Vranjes', age: 26, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Magnus Wislander', age: 36, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrei Xepkin', age: 35, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Handball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kseniya Afanasyeva', age: 20, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Krisztián Berki', age: 27, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diana Bulimar', age: 16, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Diana Maria Chelaru', age: 18, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Deng Linlin', age: 20, country: 'China', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anastasiya Grishina', age: 16, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Guo Weiyang', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fabian Hambüchen', age: 24, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'He Kexin', age: 20, country: 'China', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Larisa Iordache', age: 16, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ryohei Kato', age: 18, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Danell Leyva', age: 20, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matteo Morandi', age: 30, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sam Oldham', age: 19, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniel Purvis', age: 21, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ihor Radivilov', age: 19, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kyla Ross', age: 15, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hamilton Sabot', age: 25, country: 'France', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sui Lu', age: 20, country: 'China', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kazuhito Tanaka', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yusuke Tanaka', age: 22, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kristian Thomas', age: 23, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Beth Tweddle', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jordyn Wieber', age: 17, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Koji Yamamuro', age: 23, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yang Hak-Seon', age: 19, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Arthur Zanetti', age: 22, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Chenglong', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Epke Zonderland', age: 26, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andreea Acatrinei', age: 16, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sasha Artemev', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Raj Bhavsar', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leszek Blanik', age: 31, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thomas Bouhail', age: 22, country: 'France', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Benoît Caranobe', age: 28, country: 'France', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oksana Chusovitina', age: 33, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gervasio Deferr', age: 27, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Deng Linlin', age: 16, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gabriela Dragoi', age: 15, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anton Fokin', age: 25, country: 'Uzbekistan', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreea Grigore', age: 17, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joey Hagerty', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fabian Hambüchen', age: 20, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hong Un-Jong', age: 19, country: 'North Korea', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Huang Xu', age: 29, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jiang Yuyuan', age: 16, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Takehiro Kashima', age: 28, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Li Shanshan', age: 16, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chellsie Memmel', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Takuya Nakase', age: 25, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steliana Nistor', age: 18, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Makoto Okiguchi', age: 22, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Samantha Peszek', age: 16, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alicia Sacramone', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Koki Sakamoto', age: 21, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bridget Sloan', age: 16, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Louis Smith', age: 19, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Justin Spring', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ana Tamârjan', age: 17, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kevin Tan', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hiroyuki Tomita', age: 27, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Filip Ude', age: 22, country: 'Croatia', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oleksandr Vorobiov', age: 23, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yu Won-Cheol', age: 24, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oana Ban', age: 18, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mohini Bhardwaj', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Igor Cassina', age: 26, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jury Chechi', age: 34, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gervasio Deferr', age: 23, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jason Gatson', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Morgan Hamm', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valeriy Honcharov', age: 26, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Dae-Eun', age: 19, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Kryuchkova', age: 16, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Émilie Le Pennec', age: 16, country: 'France', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Li Xiaopeng', age: 23, country: 'China', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brett McClure', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Courtney McCool', age: 16, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hisashi Mizutori', age: 24, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Patricia Moreno', age: 16, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daisuke Nakano', age: 21, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniel Popescu', age: 21, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dan Potra', age: 26, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jevgenijs Sapronenko', age: 25, country: 'Latvia', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Razvan Selariu', age: 20, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kyle Shewfelt', age: 22, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Silvia Stroescu', age: 19, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ioan Suciu', age: 26, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dimosthenis Tambakos', age: 27, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Teng Haibin', age: 19, country: 'China', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Naoya Tsukahara', age: 27, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Blaine Wilson', age: 30, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yang Tae-Yeong', age: 24, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lyudmila Yezhova-Grebenkova', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Guard Young', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Zamolodchikova', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhang Nan', age: 18, country: 'China', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Ziganshina', age: 18, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maksim Alyoshin', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leszek Blanik', age: 23, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Loredana Boboc', age: 16, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Chepeleva', age: 16, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Amy Chow', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Szilveszter Csollány', age: 30, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jamie Dantzscher', age: 18, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dominique Dawes', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gervasio Deferr', age: 19, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Drevin', age: 18, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Valeriy Honcharov', age: 22, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Huang Xu', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andreea Isarescu', age: 16, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anastasiya Kolesnikova', age: 16, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikolay Kryukov', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ling Jie', age: 17, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kristin Maloney', age: 19, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ruslan Mezentsev', age: 19, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valeriy Pereshkura', age: 22, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yevgeny Podgorny', age: 23, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Éric Poujade', age: 28, country: 'France', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Claudia Presacan', age: 20, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elise Ray', age: 18, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tasha Schwikert-Warren', age: 15, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oleksandr Svitlychniy', age: 28, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dimosthenis Tambakos', age: 23, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marius Urzica', age: 24, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Benjamin Varonian', age: 20, country: 'France', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Igors Vihrovs', age: 22, country: 'Latvia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Xiao Junfeng', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Xing Aowei', age: 18, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yang Yun', age: 15, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zheng Lihui', age: 22, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roman Zozulia', age: 21, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alex Sandro', age: 21, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexandre Pato', age: 22, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kozue Ando', age: 30, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Javier Aquino', age: 22, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Baek Seong-Dong', age: 20, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shannon Boxx', age: 35, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rachel Buehler', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Candace Chapman', age: 29, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Darvin Chávez', age: 22, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lauren Cheney', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'José Corona', age: 31, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Javier Cortés', age: 23, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Leandro Damião', age: 23, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Danilo', age: 21, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Giovani dos Santos', age: 23, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jorge Enríquez', age: 21, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marco Fabián', age: 23, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jonelle Filigno', age: 21, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Miho Fukumoto', age: 28, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gabriel', age: 19, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ganso', age: 22, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Robyn Gayle', age: 26, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gi Seong-Yong', age: 23, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gu Ja-Cheol', age: 23, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tobin Heath', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Héctor Herrera', age: 22, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hulk', age: 26, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hwang Seok-Ho', age: 23, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mana Iwabuchi', age: 19, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Azusa Iwashimizu', age: 25, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jeong Seong-Ryong', age: 27, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeong U-Yeong', age: 22, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ji Dong-Won', age: 21, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Israel Jiménez', age: 22, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Raúl Jiménez', age: 21, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Juan', age: 21, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ayumi Kaihori', age: 25, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nahomi Kawasumi', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Bo-Gyeong', age: 22, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Chang-Su', age: 26, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Gi-Hui', age: 23, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Hyeon-Seong', age: 22, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Yeong-Gwon', age: 22, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yukari Kinga', age: 28, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Saki Kumagai', age: 21, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kaylyn Kyle', age: 23, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karina LeBlanc', age: 32, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lee Beom-Yeong', age: 23, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Amy LePeilbet', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sydney Leroux', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carli Lloyd', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lucas', age: 19, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marcelo', age: 24, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Karina Maruyama', age: 29, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Diana Matheson', age: 28, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Erin McLeod', age: 29, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hiram Mier', age: 22, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Heather Mitts', age: 34, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aya Miyama', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alex Morgan', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carmelina Moscato', age: 28, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuki Nagasato-Ogimi', age: 25, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nam Tae-Hui', age: 21, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marie-Eve Nault', age: 30, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Neto', age: 23, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Neymar', age: 20, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Kelley O'Hara", age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Heather O'Reilly", age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'O Jae-Seok', age: 22, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shinobu Ohno', age: 28, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oscar', age: 20, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Park Jong-Wu', age: 23, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Park Ju-Yeong', age: 27, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kelly Parker', age: 31, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christie Pearce-Rampone', age: 37, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Oribe Peralta', age: 28, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Miguel Ponce', age: 23, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rafael', age: 22, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Megan Rapinoe', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diego Reyes', age: 19, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Amy Rodriguez', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rômulo', age: 21, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mizuho Sakaguchi', age: 24, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carlos Salcido', age: 32, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aya Sameshima', age: 25, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sandro', age: 23, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Becky Sauerbrunn', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Homare Sawa', age: 33, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sophie Schmidt', age: 24, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Desiree Scott', age: 24, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lauren Sesselmann', age: 28, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thiago Silva', age: 27, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christine Sinclair', age: 29, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hope Solo', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chelsea Stewart', age: 22, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Megumi Takase', age: 21, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Asuna Tanaka', age: 24, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Melissa Tancredi', age: 30, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brittany Timko', age: 26, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bruno Uvini', age: 21, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Néstor Vidrio', age: 23, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Abby Wambach', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rhian Wilkinson', age: 30, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kyoko Yano', age: 28, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yun Seok-Yeong', age: 22, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lautaro Acosta', age: 20, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olubayo Adefemi', age: 22, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dele Adeleye', age: 19, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergio Agüero', age: 20, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Femi Ajilore', age: 23, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexandre Pato', age: 18, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Efe Ambrose', age: 19, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ânderson', age: 20, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andréia', age: 30, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nadine Angerer', age: 29, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Victor Anichebe', age: 20, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Onyekachi Apam', age: 21, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lira Bajramaj', age: 20, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Éver Banega', age: 20, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bárbara', age: 20, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Melanie Behringer', age: 22, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shannon Boxx', age: 31, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Breno', age: 18, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Linda Bresonik', age: 24, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rachel Buehler', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diego Buonanotte', age: 20, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lori Chalupny', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lauren Cheney', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stephanie Cox', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cristiane', age: 23, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniela', age: 24, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ángel Di María', age: 20, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diego', age: 23, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emmanuel Ekpo', age: 20, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Érika', age: 20, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ester', age: 25, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fabiana', age: 19, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Federico Fazio', age: 21, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Formiga', age: 30, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Francielle', age: 18, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fernando Gago', age: 22, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ezequiel Garay', age: 21, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kerstin Garefrekes', age: 28, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tobin Heath', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hernanes', age: 23, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ariane Hingst', age: 29, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Angela Hucles', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ilsinho', age: 22, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Promise Isaac', age: 20, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Monday James', age: 21, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jô', age: 21, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tasha Kai', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sani Kaita', age: 22, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kóki', age: 22, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Annike Krahn', age: 23, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simone Laudehr', age: 22, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ezequiel Lavezzi', age: 23, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Renate Lingor', age: 32, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carli Lloyd', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lucas', age: 21, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marcelo', age: 20, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marta', age: 22, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Javier Mascherano', age: 24, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maurine', age: 22, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maycon', age: 31, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lionel Messi', age: 21, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anja Mittag', age: 23, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Heather Mitts', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fabián Monzón', age: 21, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thiago Neves', age: 23, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Heather O'Reilly", age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Victor Obinna', age: 21, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Peter Odemwingie', age: 27, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chinedu Ogbuke', age: 22, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chibuzor Okonkwo', age: 19, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Solomon Okoronkwo', age: 21, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Célia Okoyino da Mbabi', age: 20, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nicolás Pareja', age: 24, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christie Pearce-Rampone', age: 33, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Babett Peter', age: 20, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Conny Pohlers', age: 29, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pretinha', age: 33, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Birgit Prinz', age: 30, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rafinha', age: 22, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ramires', age: 21, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Renan', age: 23, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Juan Riquelme', age: 30, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Amy Rodriguez', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sergio Romero', age: 21, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ronaldinho', age: 28, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andréia Rosa', age: 24, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rosana', age: 26, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alex Silva', age: 23, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thiago Silva', age: 23, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simone', age: 27, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sandra Smisek', age: 31, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rafael Sóbis', age: 23, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kate Sobrero-Markgraf', age: 31, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hope Solo', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'José Sosa', age: 23, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kerstin Stegemann', age: 30, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tânia Maranhão', age: 33, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lindsay Tarpley', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Óscar Ustari', age: 22, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ambruse Vanzekin', age: 22, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aly Wagner', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pablo Zabaleta', age: 23, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aline', age: 22, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andréia', age: 26, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roberto Ayala', age: 31, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Isabell Bachor', age: 21, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fredy Bareiro', age: 22, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Diego Barreto', age: 23, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Édgar Barreto', age: 20, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrea Barzagli', age: 23, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pedro Benítez', age: 23, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniele Bonera', age: 23, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cesare Bovo', age: 21, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shannon Boxx', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicolás Burdisso', age: 23, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'José Cardozo', age: 33, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brandi Chastain', age: 36, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Giorgio Chiellini', age: 19, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fabricio Coloccini', age: 22, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ernesto Cristaldo', age: 20, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cristiane', age: 19, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Andrés D'Alessandro", age: 23, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniela', age: 20, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniele De Rossi', age: 21, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simone Del Nero', age: 23, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'César Delgado', age: 22, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'José Devaca', age: 21, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Osvaldo Díaz', age: 22, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marco Donadel', age: 21, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Elaine', age: 21, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julio César Enciso', age: 30, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Celso Esquivel', age: 23, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joy Fawcett', age: 36, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matteo Ferrari', age: 24, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Diego Figueredo', age: 22, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Formiga', age: 26, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julie Foudy', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sonja Fuss', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carlos Gamarra', age: 33, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kerstin Garefrekes', age: 24, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrea Gasbarroni', age: 23, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alberto Gilardino', age: 22, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pablo Giménez', age: 23, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julio González', age: 22, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kily González', age: 30, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luis González', age: 23, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariano González', age: 23, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Grazielle', age: 23, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sarah Günther', age: 21, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mia Hamm', age: 32, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gabriel Heinze', age: 26, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ariane Hingst', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Angela Hucles', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Steffi Jones', age: 31, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Juliana', age: 22, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kelly Cristina', age: 19, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kóki', age: 18, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kristine Lilly', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Renate Lingor', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Germán Lux', age: 22, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Julio Manzur', age: 23, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marta', age: 18, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Emilio Martínez', age: 23, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Javier Mascherano', age: 20, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maycon', age: 27, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicolás Medina', age: 22, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Giandomenico Mesto', age: 22, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sandra Minnert', age: 31, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Heather Mitts', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mônica', age: 26, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Emiliano Moretti', age: 23, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martina Müller', age: 24, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Heather O'Reilly", age: 19, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Viola Odebrecht', age: 21, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Navina Omilade', age: 22, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Angelo Palombo', age: 22, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cindy Parlow', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christie Pearce-Rampone', age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ivan Pelizzoli', age: 23, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giampiero Pinzi', age: 23, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrea Pirlo', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Conny Pohlers', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pretinha', age: 29, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Birgit Prinz', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cat Reddick', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Clemente Rodríguez', age: 23, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mauro Rosales', age: 23, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rosana', age: 22, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roseli', age: 34, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Silke Rottenberg', age: 32, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Javier Saviola', age: 22, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Giuseppe Sculli', age: 23, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Briana Scurry', age: 32, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kate Sobrero-Markgraf', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kerstin Stegemann', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tânia Maranhão', age: 29, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lindsay Tarpley', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carlos Tévez', age: 20, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aureliano Torres', age: 22, country: 'Paraguay', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aly Wagner', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Abby Wambach', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Petra Wimbersky', age: 21, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pia Wunderlich', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Patrice Abanda', age: 22, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Albelda', age: 23, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicolas Alnoudji', age: 20, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cristián Álvarez', age: 20, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iván Amaya', age: 22, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Miguel Ángel Angulo', age: 23, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniel Aranzubia', age: 20, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Francisco Arrué', age: 23, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Clément Beaud', age: 19, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristin Bekkevold', age: 23, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniel Bekono', age: 22, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Serge Branco', age: 20, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicole Brandebusemeyer', age: 25, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Capdevila', age: 22, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brandi Chastain', age: 32, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pablo Contreras', age: 22, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joël Epalle', age: 22, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gro Espeseth', age: 27, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Samuel Eto'o", age: 19, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lorrie Fair', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joy Fawcett', age: 32, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jordi Ferrón', age: 22, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Doris Fitschen', age: 31, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Julie Foudy', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gabri', age: 21, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Geremi', age: 21, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sebastián González', age: 21, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeanette Götte', age: 21, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stefanie Gottschlich', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Inka Grings', age: 21, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ragnhild Gulbrandsen', age: 23, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Solveig Gulbrandsen', age: 19, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mia Hamm', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Margunn Haugenes', age: 30, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Henríquez', age: 23, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ariane Hingst', age: 21, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Melanie Hoffmann', age: 25, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Manuel Ibarra', age: 22, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christine Bøe Jensen', age: 25, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Steffi Jones', age: 27, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'José Mari', age: 21, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Silje Jørgensen', age: 23, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Idriss Carlos Kameni', age: 16, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Monica Knudsen', age: 25, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gøril Kringen', age: 28, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lacruz', age: 22, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lauren', age: 23, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Unni Lehn', age: 23, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristine Lilly', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Renate Lingor', age: 24, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Albert Luque', age: 22, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Modeste M'Bami", age: 17, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Patrick M'Boma", age: 29, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shannon MacMillan', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Claudio Maldonado', age: 20, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marchena', age: 21, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maren Meinert', age: 27, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dagny Mellgren', age: 22, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Albert Meyong Ze', age: 19, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tiffeny Milbrett', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Serge Mimpo', age: 26, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sandra Minnert', age: 27, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Claudia Müller', age: 26, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Siri Mullinix', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Reinaldo Navia', age: 22, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniel Ngom Kome', age: 20, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aaron Nguimbat', age: 22, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bente Nordby', age: 26, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rodrigo Núñez', age: 23, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rafael Olarra', age: 22, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Patricio Ormazábal', age: 21, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cindy Parlow', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christie Pearce-Rampone', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marianne Pettersen', age: 25, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Pizarro', age: 21, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Birgit Prinz', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Puyol', age: 22, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anita Rapp', age: 23, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pedro Reyes', age: 27, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hege Riise', age: 31, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mauricio Rojas', age: 22, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Silke Rottenberg', age: 28, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ismael Ruiz', age: 23, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brit Sandaune', age: 28, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nikki Serlenga', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kate Sobrero-Markgraf', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kerstin Stegemann', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Patrick Suffo', age: 22, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamudo', age: 22, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nelson Tapia', age: 33, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rodrigo Tello', age: 20, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Toni', age: 23, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anne Tønnessen', age: 26, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Unai', age: 23, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bettina Wiegmann', age: 28, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pierre Wome', age: 21, country: 'Cameroon', year: 2000, date: '01/10/2000', sport: 'Football', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tina Wunderlich', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xavi', age: 20, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iván Zamorano', age: 33, country: 'Chile', year: 2000, date: '01/10/2000', sport: 'Football', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mao Asada', age: 19, country: 'Japan', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Meryl Davis', age: 23, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oksana Domnina', age: 25, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Yeon-A', age: 19, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Evan Lysacek', age: 24, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Scott Moir', age: 22, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pang Qing', age: 30, country: 'China', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yevgeny Plyushchenko', age: 27, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joannie Rochette', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aljona Sawtchenko', age: 26, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maksim Shabalin', age: 28, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shen Xue', age: 31, country: 'China', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Robin Szolkowy', age: 30, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daisuke Takahashi', age: 23, country: 'Japan', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tong Jian', age: 30, country: 'China', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tessa Virtue', age: 20, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Charlie White', age: 22, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhao Hongbo', age: 36, country: 'China', year: 2010, date: '28/02/2010', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ben Agosto', age: 24, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shizuka Arakawa', age: 24, country: 'Japan', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tanith Belbin', age: 21, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jeff Buttle', age: 23, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sasha Cohen', age: 21, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ruslan Honcharov', age: 33, country: 'Ukraine', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olena Hrushyna', age: 31, country: 'Ukraine', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roman Kostomarov', age: 29, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stéphane Lambiel', age: 20, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maksim Marinin', age: 28, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatyana Navka', age: 30, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeny Plyushchenko', age: 23, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shen Xue', age: 27, country: 'China', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Slutskaya', age: 27, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatyana Totmyanina', age: 24, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Dan', age: 20, country: 'China', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhang Hao', age: 21, country: 'China', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhao Hongbo', age: 32, country: 'China', year: 2006, date: '26/02/2006', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marina Anissina', age: 26, country: 'France', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ilya Averbukh', age: 28, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Berezhnaya', age: 24, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Barbara Fusar Poli', age: 30, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Timothy Goebel', age: 21, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sarah Hughes', age: 16, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michelle Kwan', age: 21, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Lobacheva', age: 28, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maurizio Margaglio', age: 27, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gwendal Peizerat', age: 29, country: 'France', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Pelletier', age: 27, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeny Plyushchenko', age: 19, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jamie Salé', age: 24, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shen Xue', age: 23, country: 'China', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anton Sikharulidze', age: 25, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irina Slutskaya', age: 23, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Yagudin', age: 21, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhao Hongbo', age: 28, country: 'China', year: 2002, date: '24/02/2002', sport: 'Figure Skating', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shannon Bahrke', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dale Begg-Smith', age: 25, country: 'Australia', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hedda Berntsen', age: 33, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexandre Bilodeau', age: 22, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Grishin', age: 30, country: 'Belarus', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Audun Grønvold', age: 33, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Guo Xinxin', age: 26, country: 'China', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jennifer Heil', age: 26, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lydia Ierodiaconou-Lassila', age: 28, country: 'Australia', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marion Josserand', age: 23, country: 'France', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hannah Kearney', age: 23, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Li Nina', age: 27, country: 'China', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liu Zhongqing', age: 24, country: 'China', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreas Matt', age: 27, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ashleigh McIvor', age: 26, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeret Peterson', age: 28, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mike Schmid', age: 25, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bryon Wilson', age: 21, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dale Begg-Smith', age: 21, country: 'Australia', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alisa Camplin', age: 31, country: 'Australia', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dmitry Dashchinsky', age: 28, country: 'Belarus', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Toby Dawson', age: 27, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Han Xiaopeng', age: 22, country: 'China', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jennifer Heil', age: 22, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sandra Laoura', age: 25, country: 'France', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vladimir Lebedev', age: 21, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Evelyne Leu', age: 29, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Li Nina', age: 23, country: 'China', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mikko Ronkainen', age: 27, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kari Traa', age: 32, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shannon Bahrke', age: 21, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Veronica Brenner', age: 27, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alisa Camplin', age: 27, country: 'Australia', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Deidra Dionne', age: 20, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Richard Gay', age: 30, country: 'France', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Grishin', age: 22, country: 'Belarus', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Janne Lahtela', age: 27, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Travis Mayer', age: 19, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joe Pack', age: 23, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tae Satoya', age: 25, country: 'Japan', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kari Traa', age: 28, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleš Valenta', age: 29, country: 'Czech Republic', year: 2002, date: '24/02/2002', sport: 'Freestyle Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alaaeldin Abouelkassem', age: 21, country: 'Egypt', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valerio Aspromonte', age: 25, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Giorgio Avola', age: 23, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Suguru Awaji', age: 23, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sebastian Bachmann', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrea Baldini', age: 26, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrea Cassarà', age: 28, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kenta Chida', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Choi Byeong-Cheol', age: 30, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Choi Eun-Sook', age: 26, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Choi In-Jeong', age: 22, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Inna Deriglazova', age: 22, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tiberiu Dolniceanu', age: 24, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rares Dumitrescu', age: 28, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kamilla Gafurzyanova', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gu Bon-Gil', age: 23, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Britta Heidemann', age: 29, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Courtney Hurley', age: 21, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kelley Hurley', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeon Hui-Suk', age: 28, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeong Gil-Ok', age: 31, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeong Hyo-Jeong', age: 28, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jeong Jin-Seon', age: 28, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peter Joppich', age: 29, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olha Kharlan', age: 21, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Jeong-Hwan', age: 28, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Ji-Yeon', age: 24, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Benjamin Kleibrink', age: 27, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Larisa Korobeynikova', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikolay Kovalyov', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maya Lawrence', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lei Sheng', age: 28, country: 'China', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Li Na', age: 31, country: 'China', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rubén Limardo', age: 26, country: 'Venezuela', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luo Xiaojuan', age: 28, country: 'China', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryo Miyake', age: 21, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aldo Montano', age: 33, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nam Hyeon-Hui', age: 30, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'O Eun-Seok', age: 29, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Oh Ha-Na', age: 27, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuki Ota', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bartosz Piasecki', age: 25, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ilaria Salvatori', age: 33, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luigi Samele', age: 25, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Susie Scanlan', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aida Shanayeva', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yana Shemiakina', age: 26, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sin A-Lam', age: 25, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexandru Siri?eanu', age: 28, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Áron Szilágyi', age: 22, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luigi Tarantino', age: 39, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sofiya Velikaya', age: 27, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'André Weßels', age: 30, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Won Wu-Yeong', age: 30, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Xu Anqi', age: 20, country: 'China', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Florin Zalomir', age: 31, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'José Luis Abajo', age: 30, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robert Andrzejuk', age: 33, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bao Yingying', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Svetlana Boyko', age: 36, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ana Brânza', age: 23, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Diego Confalonieri', age: 29, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mihai Covaliu', age: 30, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emily Cross', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Britta Heidemann', age: 25, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Huang Haiyang', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jérôme Jeannet', age: 31, country: 'France', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olha Kharlan', age: 17, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olena Khomrova', age: 21, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Benjamin Kleibrink', age: 23, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeniya Lamonova', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aldo Montano', age: 29, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tim Morehouse', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tomasz Motyka', age: 27, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nam Hyeon-Hui', age: 26, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ildikó Nébaldné Mincza', age: 38, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ni Hong', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Viktoriya Nikishina', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diego Occhiuzzi', age: 27, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuki Ota', age: 22, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gianpiero Pastore', age: 32, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Julien Pillet', age: 30, country: 'France', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Halyna Pundyk', age: 20, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ulrich Robeiri', age: 25, country: 'France', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jason Rogers', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alfredo Rota', age: 33, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ilaria Salvatori', age: 29, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Boris Sanson', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Salvatore Sanzo', age: 32, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aida Shanayeva', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erinn Smart', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Keeth Smart', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tan Xue', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luigi Tarantino', age: 35, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hanna Thompson', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Giovanna Trillini', age: 38, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adam Wiercioch', age: 27, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'James Williams', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Radoslaw Zawrotniak', age: 26, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhong Man', age: 25, country: 'China', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olha Zhovnir', age: 19, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karina Aznavuryan', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gábor Boczkó', age: 27, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Éric Boisse', age: 24, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Claudia Bokel', age: 30, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sarah Daninthe', age: 24, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dong Zhaozhi', age: 30, country: 'China', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Imke Duplitzer', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Dyachenko', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jörg Fiedler', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marcel Fischer', age: 26, country: 'Switzerland', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Renal Ganeyev', age: 19, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sylwia Gruchala', age: 22, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brice Guyart', age: 23, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Britta Heidemann', age: 21, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Géza Imre', age: 29, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sada Jacobson', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fabrice Jeannet', age: 23, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jérôme Jeannet', age: 27, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hajnalka Kiraly-Picot', age: 33, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pavel Kolobkov', age: 34, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iván Kovács', age: 34, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Krisztián Kulcsár', age: 33, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tatyana Logunova', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yury Molchan', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tímea Nagy', age: 33, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ruslan Nasibulin', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zsolt Nemcsik', age: 26, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hugues Obry', age: 31, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gianpiero Pastore', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julien Pillet', age: 26, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stanislav Pozdnyakov', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vyacheslav Pozdnyakov', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sven Schmid', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Sharikov', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Sivkova', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniel Strigel', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tan Xue', age: 20, country: 'China', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luigi Tarantino', age: 31, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Damien Touya', age: 29, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gaël Touya', age: 30, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vladyslav Tretiak', age: 24, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giovanna Trillini', age: 34, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Simone Vanni', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Valentina Vezzali', age: 30, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wang Haibin', age: 30, country: 'China', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Lei', age: 23, country: 'China', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wu Hanxiong', age: 23, country: 'China', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Yakimenko', age: 20, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ye Chong', age: 34, country: 'China', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oksana Yermakova', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariel Zagunis', age: 19, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karina Aznavuryan', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sabine Bau', age: 31, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dennis Bauer', age: 19, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Diana Bianchedi', age: 30, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ralf Bißdorf', age: 29, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mihai Covaliu', age: 22, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daniele Crosta', age: 30, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jean-François Di Martino', age: 33, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dong Zhaozhi', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jean-Noël Ferrari', age: 26, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Laura Flessel-Colovic', age: 28, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Frosin', age: 22, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sylwia Gruchala', age: 18, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brice Guyart', age: 19, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Yeong-Ho', age: 29, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pavel Kolobkov', age: 30, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sophie Lamon', age: 15, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Sang-Gi', age: 34, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Patrice Lhôtellier', age: 34, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Li Na', age: 19, country: 'China', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Liang Qin', age: 28, country: 'China', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatyana Logunova', age: 20, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nelson Loyola', age: 32, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gabriele Magni', age: 26, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mariya Mazina', age: 36, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Angelo Mazzoni', age: 39, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paolo Milanoli', age: 30, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Magdalena Mroczkiewicz', age: 21, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tímea Nagy', age: 30, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carlos Pedroso', age: 33, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Julien Pillet', age: 22, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lionel Plumenail', age: 33, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stanislav Pozdnyakov', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maurizio Randazzo', age: 36, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diana Romagnoli', age: 23, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alfredo Rota', age: 25, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Rybicka', age: 23, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Salvatore Sanzo', age: 24, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cédric Séguin', age: 27, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Sharikov', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Shevchenko', age: 32, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Éric Srecki', age: 36, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Damien Touya', age: 25, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iván Trevejo', age: 28, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Haibin', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexander Weber', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Monika Weber-Koszto', age: 34, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Barbara Wolnicka-Szewczyk', age: 30, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yang Shaoqi', age: 24, country: 'China', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ye Chong', age: 30, country: 'China', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oksana Yermakova', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matteo Zennaro', age: 24, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ramzy Al-Duhami', age: 40, country: 'Saudi Arabia', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Prince Abdullah Al-Saud', age: 27, country: 'Saudi Arabia', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sara Algotsson Ostholt', age: 37, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kamal Bahamdan', age: 42, country: 'Saudi Arabia', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Scott Brash', age: 26, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Charles', age: 52, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tina Cook', age: 41, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'William Fox-Pitt', age: 43, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Edward Gal', age: 42, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Steve Guerdat', age: 30, country: 'Switzerland', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carl Hester', age: 45, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marc Houtzager', age: 41, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ingrid Klimke', age: 44, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Helen Langehanenberg', age: 30, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ben Maher', age: 29, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrew Nicholson', age: 50, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Cian O'Connor", age: 32, country: 'Ireland', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jonathan Paget', age: 28, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zara Phillips', age: 31, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Caroline Powell', age: 39, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jonelle Richards', age: 31, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dorothee Schneider', age: 43, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dirk Schrade', age: 34, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Abdullah Sharbatly', age: 29, country: 'Saudi Arabia', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nick Skelton', age: 54, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristina Sprehe', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Peter Thomsen', age: 51, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mary Thomson-King', age: 51, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mark Todd', age: 56, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maikel van der Vleuten', age: 24, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anky van Grunsven', age: 44, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jur Vrieling', age: 43, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicola Wilson', age: 35, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rolf-Göran Bengtsson', age: 46, country: 'Sweden', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nadine Capellmann', age: 43, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mac Cone', age: 55, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andreas Dibowski', age: 42, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daisy Dick', age: 36, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'William Fox-Pitt', age: 39, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Clayton Fredericks', age: 40, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lucinda Fredericks', age: 42, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steve Guerdat', age: 26, country: 'Switzerland', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreas Helgstrand', age: 30, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jill Henselwood', age: 45, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sharon Hunt', age: 30, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anne Jensen-van Olst', age: 46, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sonja Johnson', age: 40, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Megan Jones', age: 31, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ingrid Klimke', age: 40, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Laura Kraut', age: 42, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christina Liebherr', age: 29, country: 'Switzerland', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gina Miles', age: 34, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ian Millar', age: 61, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hans Peter Minderhoud', age: 34, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Frank Ostholt', age: 32, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shane Rose', age: 35, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Imke Schellekens-Bartels', age: 31, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Niklaus Schurtenberger', age: 40, country: 'Switzerland', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pius Schwizer', age: 46, country: 'Switzerland', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Will Simpson', age: 49, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Thomsen', age: 47, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mary Thomson-King', age: 47, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'McLain Ward', age: 32, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nathalie zu Sayn-Wittgenstein', age: 33, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christian Ahlmann', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Malin Baryard-Johnsson', age: 29, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Otto Becker', age: 45, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rolf-Göran Bengtsson', age: 42, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julie Black-Burns Richards', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Arnaud Boiteau', age: 30, country: 'France', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeanette Brakewell', age: 30, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Darren Chiacchia', age: 39, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Didier Courrèges', age: 44, country: 'France', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Robert Dover', age: 48, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peter Eriksson', age: 44, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'William Fox-Pitt', age: 35, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Peder Fredricson', age: 32, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juan Antonio Jiménez', age: 45, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heike Kemmer', age: 42, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cédric Lyard', age: 32, country: 'France', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Beezie Madden', age: 40, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Debbie McDonald', age: 49, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rodrigo Pessoa', age: 31, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ignacio Rambla', age: 40, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martin Schaudt', age: 45, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hubertus Schmidt', age: 44, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Guenter Seidel', age: 43, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rafael Soto', age: 46, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jean Teulère', age: 50, country: 'France', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mary Thomson-King', age: 43, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicolas Touzaint', age: 24, country: 'France', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Amy Tryon', age: 34, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anky van Grunsven', age: 36, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'McLain Ward', age: 28, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lisa Wilcox', age: 37, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'John Williams', age: 39, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peter Wylde', age: 39, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Khaled Al-Eid', age: 31, country: 'Saudi Arabia', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Otto Becker', age: 41, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ludger Beerbaum', age: 37, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Susan Blinks', age: 42, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ellen Bontje', age: 42, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jeanette Brakewell', age: 26, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nadine Capellmann', age: 35, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luiz Felipe de Azevedo', age: 47, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Doda', age: 27, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robert Dover', age: 44, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeroen Dubbeldam', age: 27, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Phillip Dutton', age: 37, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marcus Ehning', age: 26, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nina Fout', age: 41, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Markus Fuchs', age: 45, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pippa Funnell', age: 31, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'André Johannpeter', age: 37, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leslie Law', age: 35, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Karen Lende O'Connor", age: 42, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Beat Mändli', age: 30, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lesley McNaught-Mändli', age: 36, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Willi Melliger', age: 47, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lars Nieberg', age: 37, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rodrigo Pessoa', age: 27, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matt Ryan', age: 36, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Guenter Seidel', age: 40, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alexandra Simons de Ridder', age: 36, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ian Stark', age: 46, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Arjen Teeuwissen', age: 29, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stuart Tinney', age: 35, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Todd', age: 44, country: 'New Zealand', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christine Traurig', age: 43, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Coby van Baalen', age: 43, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Albert Voorn', age: 44, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Linden Wiesman', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jennifer Abel', age: 20, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Meaghan Benfeito', age: 23, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brittany Broben', age: 16, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kelci Bryant', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cao Yuan', age: 17, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tom Daley', age: 18, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Troy Dumais', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paola Espinosa', age: 26, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roseline Filion', age: 25, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iván García', age: 18, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'He Chong', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emilie Heymans', age: 30, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kristian Ipsen', age: 19, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Abby Johnston', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yevgeny Kuznetsov', age: 22, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luo Yutong', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nick McCrory', age: 20, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alejandra Orozco', age: 15, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pandelela Pamg', age: 19, country: 'Malaysia', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Qiu Bo', age: 19, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Germán Sánchez', age: 20, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laura Sánchez', age: 26, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Hao', age: 19, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Yanquan', age: 18, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bree Cole', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexandre Despatie', age: 23, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dmitry Dobroskok', age: 24, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paola Espinosa', age: 22, country: 'Mexico', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Heike Fischer', age: 25, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Patrick Hausding', age: 19, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'He Chong', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emilie Heymans', age: 26, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Huo Liang', age: 18, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sascha Klein', age: 22, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ditte Kotzian', age: 29, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yury Kunakov', age: 18, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Illia Kvasha', age: 20, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lin Yue', age: 17, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt Mitcham', age: 20, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatiana Ortíz', age: 24, country: 'Mexico', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anastasia Pozdnyakova', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oleksiy Pryhorov', age: 21, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dmitry Sautin', age: 34, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Feng', age: 29, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Melissa Wu', age: 16, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhou Luxin', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steven Barnett', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thomas Bimis', age: 29, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alexandre Despatie', age: 19, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nataliya Goncharova', age: 16, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Blythe Hartley', age: 22, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emilie Heymans', age: 22, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hu Jia', age: 21, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vera Ilyina', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuliya Koltunova', age: 15, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Irina Lashko', age: 31, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Ting', age: 17, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peng Bo', age: 23, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Sautin', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tobias Schellenberg', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikolaos Siranidis', age: 28, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Leon Taylor', age: 26, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Loudy Tourky-Wiggins', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peter Waterfield', age: 23, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andreas Wels', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yang Jinghui', age: 21, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Dobroskok', age: 18, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rebecca Gilmore', age: 21, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jan Hempel', age: 29, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emilie Heymans', age: 18, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vera Ilyina', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dörte Lindner', age: 26, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Igor Lukashin', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Heiko Meyer', age: 23, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robert Newbery', age: 21, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuliya Pakhalina', age: 23, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fernando Platas', age: 27, country: 'Mexico', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dean Pullar', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sang Xue', age: 16, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hanna Sorokina', age: 24, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Loudy Tourky-Wiggins', age: 21, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura Wilkinson', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Xiao Hailiang', age: 23, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olena Zhupina', age: 27, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lizzie Armitstead', age: 23, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kristin Armstrong', age: 38, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Judith Arndt', age: 36, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dotsie Bausch', age: 39, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sam Bewley', age: 25, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jack Bobridge', age: 23, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julie Bresset', age: 23, country: 'France', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Steven Burke', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gillian Carleton', age: 22, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bryan Coquard', age: 20, country: 'France', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Michaël D'Almeida", age: 24, country: 'France', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rohan Dennis', age: 22, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Annette Edmondson', age: 20, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'René Enders', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marco Aurelio Fontana', age: 27, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robert Förstemann', age: 26, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chris Froome', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aaron Gate', age: 21, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jasmin Glaesser', age: 20, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gong Jinjie', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Westley Gough', age: 24, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Georgia Gould', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lasse Norman Hansen', age: 20, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michael Hepburn', age: 20, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Philip Hindes', age: 19, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Kennaugh', age: 23, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dani King', age: 21, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alexander Kristoff', age: 25, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jaroslav Kulhavý', age: 27, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lee Wai Sze', age: 25, country: 'Hong Kong', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tony Martin', age: 27, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kaarle McCulloch', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Teun Mulder', age: 31, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Glenn O'Shea", age: 23, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carlos Oquendo', age: 24, country: 'Colombia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mariana Pajón', age: 20, country: 'Colombia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shane Perkins', age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jennie Reed', age: 34, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joanna Rowsell', age: 23, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marc Ryan', age: 29, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nino Schurter', age: 26, country: 'Switzerland', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jesse Sergent', age: 24, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kévin Sireau', age: 25, country: 'France', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laura Smulders', age: 18, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sabine Spitz', age: 40, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maris Štrombergs', age: 25, country: 'Latvia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lauren Tamayo', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Geraint Thomas', age: 26, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rigoberto Urán', age: 25, country: 'Colombia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Simon van Velthooven', age: 23, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Vinokurov', age: 38, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristina Vogel', age: 21, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marianne Vos', age: 25, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sarah Walker', age: 24, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Miriam Welte', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tara Whitten', age: 32, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bradley Wiggins', age: 32, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sam Willoughby', age: 20, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julien Absalon', age: 28, country: 'France', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristin Armstrong', age: 35, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Grégory Baugé', age: 23, country: 'France', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sam Bewley', age: 21, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Steven Burke', age: 20, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anne-Caroline Chausson', age: 30, country: 'France', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michael Færk Christensen', age: 22, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ed Clancy', age: 23, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicole Cooke', age: 25, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Juan Esteban Curuchet', age: 43, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mike Day', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ross Edgar', age: 25, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'René Enders', age: 21, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yoanka González', age: 32, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Westley Gough', age: 20, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tania Guderzo', age: 23, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Guo Shuang', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wendy Houvenaghel', age: 33, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mikhail Ignatyev', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emma Johansson', age: 24, country: 'Sweden', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Casper Jørgensen', age: 22, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Irina Kalentyeva', age: 30, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lesia Kalytovska', age: 20, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jill Kintner', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roger Kluge', age: 22, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandr Kolobnev', age: 27, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gustav Larsson', age: 27, country: 'Sweden', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laëtitia Le Corguillé', age: 22, country: 'France', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Levi Leipheimer', age: 34, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maximilian Levy', age: 21, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jens-Erik Madsen', age: 27, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paul Manning', age: 33, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Markov', age: 29, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Meares', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Mørkøv', age: 23, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kiyofumi Nagai', age: 25, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chris Newton', age: 34, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stefan Nimke', age: 30, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leire Olaberria', age: 31, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vicki Pendleton', age: 27, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jean-Christophe Péraud', age: 31, country: 'France', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Walter Pérez', age: 35, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emma Pooley', age: 25, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alex Rasmussen', age: 24, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Donny Robinson', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rebecca Romero', age: 28, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marc Ryan', age: 25, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Samuel Sánchez', age: 30, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nino Schurter', age: 22, country: 'Switzerland', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jesse Sergent', age: 20, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kévin Sireau', age: 21, country: 'France', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sabine Spitz', age: 36, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jamie Staff', age: 35, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maris Štrombergs', age: 21, country: 'Latvia', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Toni Tauler', age: 34, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Geraint Thomas', age: 22, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karin Thürig', age: 36, country: 'Switzerland', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Arnaud Tournant', age: 30, country: 'France', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marianne Vos', age: 21, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maja Wloszczowska', age: 24, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tamila Abasova', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julien Absalon', age: 24, country: 'France', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Judith Arndt', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paolo Bettini', age: 30, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Theo Bos', age: 21, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mickaël Bourgain', age: 24, country: 'France', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bart Brentjens', age: 35, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'María Luisa Calle', age: 35, country: 'Colombia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sara Carrigan', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carlos Castaño', age: 25, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Steve Cummings', age: 23, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gunn Rita Dahle-Flesjå', age: 31, country: 'Norway', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Dawson', age: 22, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dede Demet-Barry', age: 31, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'José Antonio Escuredo', age: 34, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jens Fiedler', age: 34, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Guido Fulst', age: 34, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Toshiaki Fushimi', age: 28, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laurent Gané', age: 31, country: 'France', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Belem Guerrero', age: 30, country: 'Mexico', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tyler Hamilton', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'José Antonio Hermida', age: 26, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chris Hoy', age: 28, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mikhail Ignatyev', age: 19, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Masaki Inoue', age: 25, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jiang Yonghua', age: 30, country: 'China', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bobby Julich', age: 32, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shane Kelly', age: 32, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brett Lancaster', age: 24, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Joan Llaneras', age: 35, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katie Mactier', age: 29, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Asier Maeztu', age: 26, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paul Manning', age: 29, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Franco Marvulli', age: 25, country: 'Switzerland', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Axel Merckx', age: 32, country: 'Belgium', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lori-Ann Muenzer', age: 38, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tomohiro Nagatsuka', age: 25, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chris Newton', age: 30, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Stuart O'Grady", age: 31, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sérgio Paulinho', age: 24, country: 'Portugal', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marie-Hélène Prémont', age: 26, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bruno Risi', age: 35, country: 'Switzerland', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luke Roberts', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sabine Spitz', age: 32, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bryan Steel', age: 35, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Karin Thürig', age: 32, country: 'Switzerland', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carlos Torrent', age: 29, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Tsilinskaya', age: 28, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sarah Ulmer', age: 28, country: 'New Zealand', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stephen Wooldridge', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vyacheslav Yekimov', age: 38, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brett Aitken', age: 29, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lance Armstrong', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniel Becke', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antonella Bellutti', age: 31, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Barbara Blatter', age: 29, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Serhiy Cherniavskiy', age: 24, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jonny Clay', age: 37, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marion Clignet', age: 36, country: 'France', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Étienne De Wilde', age: 42, country: 'Belgium', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sean Eadie', age: 31, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oleksandr Fedenko', age: 29, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michelle Ferris', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marga Fullana', age: 28, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Guido Fulst', age: 30, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Laurent Gané', age: 27, country: 'France', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matthew Gilmore', age: 28, country: 'Belgium', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oksana Grishina', age: 31, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Darryn Hill', age: 26, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mari Holden', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chris Hoy', age: 24, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jiang Cuihua', age: 25, country: 'China', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shane Kelly', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreas Klöden', age: 25, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hanka Kupfernagel', age: 26, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joan Llaneras', age: 31, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeannie Longo-Ciprelli', age: 41, country: 'France', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Craig MacLean', age: 29, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paul Manning', age: 25, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Markov', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Silvio Martinello', age: 37, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Miguel Martinez', age: 24, country: 'France', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Serhiy Matvieiev', age: 25, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brad McGee', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yvonne McGregor', age: 39, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Scott McGrory', age: 30, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Filip Meirhaeghe', age: 29, country: 'Belgium', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chris Newton', age: 26, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stefan Nimke', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marty Nothstein', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paola Pezzo', age: 31, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olaf Pollack', age: 26, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christoph Sauser', age: 24, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olga Slyusareva', age: 31, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bryan Steel', age: 31, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oleksandr Symonenko', age: 26, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Arnaud Tournant', age: 22, country: 'France', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marco Villa', age: 31, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Vinokurov', age: 27, country: 'Kazakhstan', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bradley Wiggins', age: 20, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Milton Wynants', age: 28, country: 'Uruguay', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iryna Yanovych', age: 24, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vyacheslav Yekimov', age: 34, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diana Žiliute', age: 24, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cori Bartel', age: 38, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cheryl Bernard', age: 43, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carolyn Darbyshire-McRory', age: 46, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Markus Eggler', age: 41, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adam Enright', age: 26, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jan Hauser', age: 25, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ben Hebert', age: 26, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marc Kennedy', age: 28, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cathrine Lindahl', age: 39, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Liu Yin', age: 28, country: 'China', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eva Lund', age: 38, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kevin Martin', age: 43, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristie Moore', age: 30, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'John Morris', age: 31, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Torger Nergård', age: 35, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anette Norberg', age: 43, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Susan O'Connor", age: 32, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Håvard Vad Petersson', age: 26, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ralph Stöckli', age: 33, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simon Strübin', age: 30, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christoffer Svae', age: 27, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anna Svärd-Le Moine', age: 36, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thomas Ulsrud', age: 38, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Bingyu', age: 25, country: 'China', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yue Qingshuang', age: 24, country: 'China', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhou Yan', age: 27, country: 'China', year: 2010, date: '28/02/2010', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mike Adam', age: 24, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Glenys Bakker', age: 43, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Binia Beeli', age: 27, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pete Fenson', age: 37, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brad Gushue', age: 25, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Russ Howard', age: 49, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sandra Jenkins', age: 44, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christine Keshen', age: 28, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kalle Kiiskinen', age: 30, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shannon Kleibrink', age: 37, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jamie Korab', age: 26, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cathrine Lindahl', age: 35, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eva Lund', age: 34, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wille Mäkelä', age: 31, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michèle Moser', age: 26, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mark Nichols', age: 26, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Amy Nixon', age: 28, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anette Norberg', age: 39, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mirjam Ott', age: 34, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joe Polo', age: 23, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shawn Rojeski', age: 34, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Teemu Salo', age: 32, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'John Shuster', age: 23, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Valeria Spälty', age: 22, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anna Svärd-Le Moine', age: 32, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Markku Uusipaavalniemi', age: 39, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Don Bartlett', age: 41, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laurence Bidaud', age: 33, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Flemming Davanger', age: 38, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luzia Ebnöther', age: 30, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Markus Eggler', age: 33, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tanya Frei', age: 29, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Damian Grichting', age: 28, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Debbie Knox', age: 33, country: 'Great Britain', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kelley Law', age: 36, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fiona MacDonald', age: 27, country: 'Great Britain', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kevin Martin', age: 35, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rhona Martin', age: 35, country: 'Great Britain', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Margaret Morton', age: 34, country: 'Great Britain', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diane Nelson', age: 43, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Torger Nergård', age: 27, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cheryl Noble', age: 45, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mirjam Ott', age: 30, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bent Ånund Ramsfjell', age: 34, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marco Ramstein', age: 23, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Janice Rankin', age: 30, country: 'Great Britain', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nadia Röthlisberger', age: 29, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carter Rycroft', age: 24, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andi Schwaller', age: 31, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christof Schwaller', age: 35, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Julie Sutton-Skinner', age: 33, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ken Tralnberg', age: 45, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pål Trulsen', age: 39, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lars Vågberg', age: 34, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Don Walchuk', age: 38, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Georgina Wheatcroft', age: 36, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Curling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tobias Angerer', age: 32, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lars Berger', age: 30, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dario Cologna', age: 23, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Miriam Gössner', age: 19, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Odd-Bjørn Hjelmeset', age: 38, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martin Jakš', age: 23, country: 'Czech Republic', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Therese Johaug', age: 21, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irina Khazova', age: 25, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Korostelyova', age: 28, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martin Koukal', age: 31, country: 'Czech Republic', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikita Kryukov', age: 24, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Virpi Kuitunen', age: 33, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Riitta-Liisa Lassila-Roponen', age: 31, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jirí Magál', age: 32, country: 'Czech Republic', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Petra Majdic', age: 30, country: 'Slovenia', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikolay Morilov', age: 23, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pirjo Muranen', age: 28, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Panzhinsky', age: 20, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Øystein Pettersen', age: 27, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Petukhov', age: 26, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pietro Piller Cottrer', age: 35, country: 'Italy', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniel Richardsson', age: 27, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vibeke Skofterud', age: 29, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristina Šmigun-Vähi', age: 32, country: 'Estonia', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anders Södergren', age: 32, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristin Størmer Steira', age: 28, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Martin Johnsrud Sundby', age: 25, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tim Tscharnke', age: 20, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katrin Zeller', age: 30, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ivan Alypov', age: 23, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lina Andersson', age: 24, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nataliya Baranova', age: 30, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lukáš Bauer', age: 28, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Viola Bauer', age: 29, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marit Bjørgen', age: 25, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stefanie Böhler', age: 24, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mikhail Botvinov', age: 38, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Antonella Confortola-Wyatt', age: 30, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chandra Crawford', age: 22, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Dahlberg-Olsson', age: 29, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roddy Darragon', age: 22, country: 'France', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Frode Estil', age: 33, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jens Filbrich', age: 26, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Arianna Follis', age: 28, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mathias Fredriksson', age: 33, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tor-Arne Hetland', age: 32, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Justyna Kowalczyk', age: 23, country: 'Poland', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Virpi Kuitunen', age: 29, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Larisa Kurkina', age: 32, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mats Larsson', age: 25, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Johan Olsson', age: 25, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gabriella Paruzzi', age: 36, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hilde Gjermundshaug Pedersen', age: 41, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sara Renner', age: 29, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vasily Rochev', age: 25, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aino-Kaisa Saarinen', age: 27, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Evi Sachenbacher-Stehle', age: 25, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andreas Schlütter', age: 33, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Beckie Scott', age: 31, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alyona Sidko', age: 26, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anders Södergren', age: 28, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'René Sommerfeldt', age: 31, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jens Arne Svartedal', age: 30, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fulvio Valbusa', age: 37, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sabina Valbusa', age: 34, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrus Veerpalu', age: 35, country: 'Estonia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cristian Zorzi', age: 33, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brigitte Albrecht-Loretan', age: 31, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tobias Angerer', age: 24, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anders Aukland', age: 29, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marit Bjørgen', age: 21, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mikhail Botvinov', age: 34, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Giorgio Di Centa', age: 29, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Per Elofsson', age: 24, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jens Filbrich', age: 22, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Manuela Henkel', age: 27, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tor-Arne Hetland', age: 28, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Odd-Bjørn Hjelmeset', age: 30, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christian Hoffmann', age: 27, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrea Huber', age: 26, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mikhail Ivanov', age: 24, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Claudia Künzel-Nystad', age: 24, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Natascia Leonardi Cortesi', age: 30, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jaak Mae', age: 29, country: 'Estonia', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fabio Maj', age: 31, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gabriella Paruzzi', age: 32, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hilde Gjermundshaug Pedersen', age: 37, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pietro Piller Cottrer', age: 27, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laurence Rochat', age: 22, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peter Schlickenrieder', age: 32, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andreas Schlütter', age: 29, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Beckie Scott', age: 27, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'René Sommerfeldt', age: 27, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hannes Aigner', age: 23, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tim Baillie', age: 33, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Bogdanovich', age: 30, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrey Bogdanovich', age: 24, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sebastian Brendel', age: 24, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Cal', age: 29, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lisa Carrington', age: 23, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yuriy Cheban', age: 26, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maialen Chourraut', age: 29, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jacob Clear', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Saúl Craviotto', age: 27, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mark de Jonge', age: 28, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rudolf Dombi', age: 25, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Josef Dostál', age: 19, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Dyachenko', age: 22, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tony Estanguet', age: 34, country: 'France', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Krisztina Fazekas Zur', age: 32, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emilie Fer', age: 29, country: 'France', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Florence', age: 29, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jess Fox', age: 18, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bridgitte Hartley', age: 29, country: 'South Africa', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniel Havel', age: 20, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Liam Heath', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pavol Hochschorner', age: 32, country: 'Slovakia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peter Hochschorner', age: 32, country: 'Slovakia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Max Hoff', age: 29, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martin Hollstein', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Richard Hounslow', age: 30, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vavrinec Hradílek', age: 25, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andreas Ihle', age: 33, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zoltán Kammerer', age: 34, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olga Khudenko', age: 20, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roland Kökény', age: 36, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Korovashkov', age: 20, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peter Kretschmer', age: 20, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamás Kulifai', age: 23, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kurt Kuschela', age: 23, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eirik Verås Larsen', age: 36, country: 'Norway', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carolin Leonhardt', age: 27, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vadim Makhnyov', age: 32, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michal Martikán', age: 33, country: 'Slovakia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ed McKeever', age: 28, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Beata Mikolajczyk', age: 26, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniele Molmenti', age: 27, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karolina Naja', age: 22, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mark Oldershaw', age: 29, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dániel Pauman', age: 25, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ilya Pervukhin', age: 21, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roman Petrushenko', age: 31, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fernando Pimenta', age: 22, country: 'Portugal', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marina Poltoran', age: 24, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Pomelova', age: 22, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nadezhda Popok', age: 23, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yury Postrigay', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jon Schofield', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ivan Shtyl', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emanuel Silva', age: 26, country: 'Portugal', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dave Smith', age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tate Smith', age: 30, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jan Šterba', age: 31, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Murray Stewart', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Etienne Stott', age: 33, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jevgenijus Šuklinas', age: 26, country: 'Lithuania', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gabriella Szabó', age: 25, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sideris Tasiadis', age: 22, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dávid Tóth', age: 27, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lukáš Trefil', age: 23, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adam Van Koeverden', age: 30, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katrin Wagner-Augustin', age: 34, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Abalmasov', age: 28, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lutz Altepost', age: 26, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rob Bell', age: 30, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Bogdanovich', age: 26, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Bogdanovich', age: 20, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Benjamin Boukpeti', age: 27, country: 'Togo', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Norman Bröckl', age: 21, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuriy Cheban', age: 22, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Saúl Craviotto', age: 23, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hannah Davis', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marie Delattre', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Torsten Eckbrett', age: 24, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrea Facchin', age: 29, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fanny Fischer', age: 21, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Florence', age: 26, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lyndsie Fogarty', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Björn Goldschmidt', age: 28, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alexander Grimm', age: 21, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Thomas Hall', age: 26, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pavol Hochschorner', age: 28, country: 'Slovakia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Hochschorner', age: 28, country: 'Slovakia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Martin Hollstein', age: 21, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Josefa Idem-Guerrini', age: 43, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andreas Ihle', age: 29, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elena Kaliská', age: 36, country: 'Slovakia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamás Kiss', age: 21, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Knudsen', age: 30, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandr Kostoglod', age: 34, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Danuta Kozák', age: 21, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'György Kozmann', age: 30, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mikhail Kuznetsov', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dmitry Larionov', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eirik Verås Larsen', age: 32, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jacqui Lawrence', age: 26, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fabien Lefèvre', age: 26, country: 'France', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Artur Litvinchuk', age: 20, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michal Martikán', age: 29, country: 'Slovakia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chantal Meek', age: 29, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Meng Guanliang', age: 31, country: 'China', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Beata Mikolajczyk', age: 22, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Violetta Oblinger-Peters', age: 30, country: 'Austria', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lisa Oldenhof', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maksim Opalev', age: 29, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Inna Osypenko-Radomska', age: 25, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aneta Pastuszka-Konieczna', age: 30, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carlos Pérez', age: 29, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'René Poulsen', age: 19, country: 'Denmark', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ronald Rauhe', age: 26, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nicole Reinhardt', age: 22, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michal Riszdorfer', age: 31, country: 'Slovakia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Richard Riszdorfer', age: 27, country: 'Slovakia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Antonio Scaduto', age: 30, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ondrej Štepánek', age: 28, country: 'Czech Republic', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gabriella Szabó', age: 22, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juraj Tarr', age: 29, country: 'Slovakia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Ulegin', age: 30, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Attila Vajda', age: 25, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adam Van Koeverden', age: 26, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anne-Laure Viard', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Erik Vlcek', age: 26, country: 'Slovakia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jaroslav Volf', age: 28, country: 'Czech Republic', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Conny Wassmuth', age: 25, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tim Wieskötter', age: 29, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yang Wenjun', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Juraj Baca', age: 27, country: 'Slovakia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Björn Bach', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hanna Balabanova', age: 34, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ledys Balceiro', age: 29, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marcus Becker', age: 22, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Beniamino Bonomi', age: 36, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kinga Bóta', age: 27, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Caroline Brunet', age: 35, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olena Cherevatova', age: 34, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tony Estanguet', age: 26, country: 'France', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nils Olav Fjeldheim', age: 27, country: 'Norway', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ben Fouhy', age: 25, country: 'New Zealand', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rebecca Giddens', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christian Gille', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stefan Henze', age: 23, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pavol Hochschorner', age: 24, country: 'Slovakia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Hochschorner', age: 24, country: 'Slovakia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gábor Horváth', age: 32, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Josefa Idem-Guerrini', age: 39, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andreas Ihle', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elena Kaliská', age: 32, country: 'Slovakia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zoltán Kammerer', age: 26, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'György Kolonics', age: 32, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'György Kozmann', age: 26, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fabien Lefèvre', age: 22, country: 'France', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vadim Makhnyov', age: 24, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michal Martikán', age: 25, country: 'Slovakia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Meng Guanliang', age: 27, country: 'China', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Henrik Nilsson', age: 28, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maike Nollen', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maksim Opalev', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Markus Oscarsson', age: 27, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Inna Osypenko-Radomska', age: 21, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aneta Pastuszka-Konieczna', age: 26, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Benoît Peschier', age: 24, country: 'France', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roman Petrushenko', age: 23, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stefan Pfannmöller', age: 23, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ronald Rauhe', age: 22, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Helen Reeves', age: 23, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michal Riszdorfer', age: 27, country: 'Slovakia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Richard Riszdorfer', age: 23, country: 'Slovakia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Clint Robinson', age: 32, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ibrahim Rojas', age: 28, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Antonio Rossi', age: 35, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Beata Sokolowska-Kulesza', age: 30, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ondrej Štepánek', age: 24, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Botond Storcz', age: 29, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Szilvia Szabó', age: 25, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tetiana Teklian-Semykina', age: 30, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stefan Ulm', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Attila Vajda', age: 21, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ákos Vereckei', age: 26, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erzsébet Viski', age: 24, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Erik Vlcek', age: 22, country: 'Slovakia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jaroslav Volf', age: 24, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Katrin Wagner-Augustin', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Campbell Walsh', age: 26, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tim Wieskötter', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tomasz Wylenzek', age: 21, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ian Wynne', age: 30, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yang Wenjun', age: 20, country: 'China', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Zabel', age: 31, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Björn Bach', age: 24, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ledys Balceiro', age: 25, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pawel Baraszkiewicz', age: 23, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anne-Lise Bardet', age: 30, country: 'France', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Krisztián Bártfai', age: 26, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dariusz Bialkowski', age: 30, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Beniamino Bonomi', age: 32, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katrin Borchert', age: 31, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tim Brabants', age: 23, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Caroline Brunet', age: 31, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Danny Collins', age: 29, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tony Estanguet', age: 22, country: 'France', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pierpaolo Ferrazzi', age: 35, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Steve Giles', age: 28, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brigitte Guibal', age: 29, country: 'France', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Štepánka Hilgertová', age: 32, country: 'Czech Republic', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pavol Hochschorner', age: 21, country: 'Slovakia', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Hochschorner', age: 21, country: 'Slovakia', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gábor Horváth', age: 28, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Josefa Idem-Guerrini', age: 36, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Raluca Ionita', age: 24, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniel Jedraszko', age: 24, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marek Jiras', age: 22, country: 'Czech Republic', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rita Kobán', age: 35, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lars Kober', age: 23, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michael Kolganov', age: 25, country: 'Israel', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'György Kolonics', age: 28, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Grzegorz Kotowicz', age: 27, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Krzysztof Kolomanski', age: 27, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariana Limbau', age: 23, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tomáš Máder', age: 26, country: 'Czech Republic', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michal Martikán', age: 21, country: 'Slovakia', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juraj Mincík', age: 23, country: 'Slovakia', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Manuela Mucke', age: 25, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Henrik Nilsson', age: 24, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ferenc Novák', age: 31, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maksim Opalev', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Markus Oscarsson', age: 23, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aneta Pastuszka-Konieczna', age: 22, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leobaldo Pereira', age: 28, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Imre Pulai', age: 32, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elena Radu', age: 25, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paul Ratcliffe', age: 26, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ronald Rauhe', age: 18, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ibrahim Rojas', age: 24, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Antonio Rossi', age: 31, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jan Schäfer', age: 25, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Thomas Schmidt', age: 24, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anett Schuck', age: 30, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adam Seroczynski', age: 26, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Beata Sokolowska-Kulesza', age: 26, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michal Staniszewski', age: 27, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sanda Toma', age: 30, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrew Trim', age: 31, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stefan Ulm', age: 24, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stefan Uteß', age: 25, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Krisztián Veréb', age: 23, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ákos Vereckei', age: 23, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erzsébet Viski', age: 20, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tim Wieskötter', age: 21, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marek Witkowski', age: 26, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mark Zabel', age: 27, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brett Anderson', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jake Arrieta', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brian Barden', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alexei Bell', age: 24, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bong Jung-Keun', age: 28, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt Brown', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Trevor Cahill', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Frederich Cepeda', age: 28, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jeremy Cummings', age: 31, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alfredo Despaigne', age: 22, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jason Donald', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brian Duensing', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giorvis Duvergel', age: 28, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michel Enríquez', age: 29, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dexter Fowler', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'John Gall', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gang Min-Ho', age: 22, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Go Yeong-Min', age: 24, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Norberto González', age: 28, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yulieski Gourriel', age: 24, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gwon Hyeok', age: 24, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Han Gi-Ju', age: 21, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mike Hessman', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jang Won-Sam', age: 25, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeong Dae-Hyeon', age: 29, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeong Geun-U', age: 25, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kevin Jepsen', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jin Gab-Yong', age: 34, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Dong-Ju', age: 32, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Gwang-Hyeon', age: 20, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Hyeon-Su', age: 20, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Min-Jae', age: 35, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brandon Knight', age: 32, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mike Koplove', age: 31, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Miguel La Hera', age: 23, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Matt LaPorta', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pedro Luis Lazo', age: 35, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Dae-Ho', age: 26, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lee Jin-Yeong', age: 28, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lee Jong-Uk', age: 28, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lee Seung-Yeop', age: 31, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lee Taek-Geun', age: 28, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lee Yong-Gyu', age: 22, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lou Marson', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jonder Martínez', age: 30, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexander Mayeta', age: 31, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rolando Meriño', age: 37, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luis Miguel Navas', age: 28, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Blaine Neal', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jayson Nix', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'O Seung-Hwan', age: 26, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vicyohandri Odelín', age: 28, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Héctor Olivera Jr.', age: 23, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adiel Palma', age: 37, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eduardo Paret', age: 35, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Park Jin-Man', age: 31, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yadier Pedroso', age: 22, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ariel Pestano', age: 34, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luis Miguel Rodríguez', age: 35, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ryu Hyeon-Jin', age: 21, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elier Sánchez', age: 21, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eriel Sánchez', age: 33, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nate Schierholtz', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Song Seung-Jun', age: 28, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeff Stevens', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stephen Strasburg', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Taylor Teagarden', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Terry Tiffee', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yoandri Urgellés', age: 27, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Norge Luis Vera', age: 37, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Casey Weathers', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yoon Suk-Min', age: 22, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryoji Aikawa', age: 28, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Craig Anderson', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuya Ando', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Danny Betancourt', age: 23, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luis Borroto', age: 21, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tom Brice', age: 22, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adrian Burnside', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Frederich Cepeda', age: 24, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yorelvis Charles', age: 25, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michel Enríquez', age: 25, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gavin Fingleson', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Atsushi Fujimoto', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kosuke Fukudome', age: 27, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Norberto González', age: 24, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paul Gonzalez', age: 35, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yulieski Gourriel', age: 20, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hirotoshi Ishii', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hisashi Iwakuma', age: 23, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hitoki Iwase', age: 29, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kenji Johjima', age: 28, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Makoto Kaneko', age: 28, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nick Kimpton', age: 20, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Takuya Kimura', age: 32, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brendan Kingman', age: 31, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Masahide Kobayashi', age: 30, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hiroki Kuroda', age: 29, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pedro Luis Lazo', age: 31, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Craig Lewis', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Graeme Lloyd', age: 37, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roger Machado', age: 30, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jonder Martínez', age: 26, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daisuke Matsuzaka', age: 23, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Danny Miranda', age: 25, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Daisuke Miura', age: 30, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shinya Miyamoto', age: 33, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Frank Montieth', age: 19, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Arihito Muramatsu', age: 31, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Norihiro Nakamura', age: 31, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dave Nilsson', age: 34, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vicyohandri Odelín', age: 24, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Trent Oeltjen', age: 21, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michihiro Ogasawara', age: 30, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wayne Ough', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chris Oxspring', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adiel Palma', age: 33, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eduardo Paret', age: 31, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ariel Pestano', age: 30, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alexei Ramírez', age: 22, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brett Roneberg', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ryan Rowland Smith', age: 21, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eriel Sánchez', age: 29, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antonio Scull', age: 38, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Naoyuki Shimizu', age: 28, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'John Stephens', age: 24, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Phil Stockman', age: 24, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carlos Tabares', age: 30, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yoshinobu Takahashi', age: 29, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brett Tamburrino', age: 22, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yoshitomo Tani', age: 31, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Richard Thompson', age: 20, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Koji Uehara', age: 29, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yoandri Urgellés', age: 23, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Osmani Urrutia', age: 28, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrew Utting', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rodney Van Buizen', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Manuel Vega', age: 29, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Norge Luis Vera', age: 33, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kazuhiro Wada', age: 32, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tsuyoshi Wada', age: 23, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ben Wigmore', age: 22, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Glenn Williams', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jeff Williams', age: 32, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brent Abernathy', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kurt Ainsworth', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Omar Ajete', age: 35, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yosvany Aragón', age: 26, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pat Borders', age: 37, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sean Burroughs', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Miguel Caldés', age: 29, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Danel Castro', age: 24, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'José Contreras', age: 28, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'John Cotton', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Travis Dawkins', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yobal Dueñas', age: 28, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adam Everett', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryan Franklin', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris George', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yasser Gómez', age: 20, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gu Dae-Seong', age: 31, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shane Heams', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hong Seong-Heun', age: 23, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'José Ibar', age: 31, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Im Chang-Yong', age: 24, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Im Seon-Dong', age: 27, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jang Seong-Ho', age: 22, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marcus Jensen', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jeong Dae-Hyeon', age: 21, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeong Min-Tae', age: 30, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeong Su-Geun', age: 23, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jin Pil-Jung', age: 27, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Dong-Ju', age: 24, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Gi-Tae', age: 31, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Han-Su', age: 28, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Su-Gyeong', age: 21, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Tae-Gyun', age: 29, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Orestes Kindelán', age: 35, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mike Kinkade', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rick Krivda', age: 30, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pedro Luis Lazo', age: 27, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Byeong-Gyu', age: 25, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lee Seung-Ho', age: 19, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lee Seung-Yeop', age: 24, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Omar Linares', age: 32, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oscar Macias', age: 31, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juan Manrique', age: 33, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Javier Méndez', age: 36, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rolando Meriño', age: 29, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Germán Mesa', age: 33, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Doug Mientkiewicz', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mike Neill', age: 30, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roy Oswalt', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antonio Pacheco', age: 36, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Park Gyeong-Wan', age: 28, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Park Jae-Hong', age: 27, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Park Jin-Man', age: 23, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Park Jong-Ho', age: 27, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Park Seok-Jin', age: 28, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ariel Pestano', age: 26, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gabriel Pierre', age: 33, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jon Rauch', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maels Rodríguez', age: 20, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anthony Sanders', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antonio Scull', age: 35, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bobby Seay', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ben Sheets', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Son Min-Han', age: 25, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Song Jin-U', age: 34, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Luis Ulacia', age: 36, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lazaro Valle', age: 37, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Norge Luis Vera', age: 29, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brad Wilkerson', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Todd Williams', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ernie Young', age: 31, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tim Young', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Baseball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicola Adams', age: 29, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Misha Aloyan', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lázaro Álvarez', age: 21, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adriana Araújo', age: 31, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Abbos Atayev', age: 26, country: 'Uzbekistan', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Ayrapetyan', age: 28, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paddy Barnes', age: 25, country: 'Ireland', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Denys Berinchyk', age: 24, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roberto Cammarelle', age: 32, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luke Campbell', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mavzuna Choriyeva', age: 19, country: 'Tajikistan', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michael Conlan', age: 20, country: 'Ireland', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ivan Dychko', age: 21, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marlen Esparza', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fred Evans', age: 21, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Esquiva Florentino', age: 22, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yamaguchi Florentino', age: 24, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Han Sun-Cheol', age: 27, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oleksandr Hvozdyk', age: 25, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roniel Iglesias', age: 23, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anthony Joshua', age: 22, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'M. C. Mary Kom', age: 29, country: 'India', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Jinzi', age: 22, country: 'China', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vasyl Lomachenko', age: 24, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vincenzo Mangiacapre', age: 23, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yegor Mekhontsev', age: 27, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ryota Murata', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'M?h?mm?dr?sul M?cidov', age: 25, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Teymur M?mm?dov', age: 19, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'John Joe Nevin', age: 23, country: 'Ireland', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adilbek Niyazymbetov', age: 23, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nyambayaryn Tögstsogt', age: 20, country: 'Mongolia', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sofya Ochigava', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anthony Ogogo', age: 23, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Evaldas Petrauskas', age: 20, country: 'Lithuania', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kaeo Pongprayoon', age: 32, country: 'Thailand', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tervel Pulev', age: 29, country: 'Bulgaria', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robeisy Ramírez', age: 18, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ren Cancan', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Clemente Russo', age: 30, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Serik Sapiyev', age: 28, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Taras Shelestiuk', age: 26, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Claressa Shields', age: 17, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Satoshi Shimizu', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Katie Taylor', age: 26, country: 'Ireland', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yasnier Toledo', age: 22, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nadezhda Torlopova', age: 33, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Uranchimegiin Mönkh-Erdene', age: 30, country: 'Mongolia', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oleksandr Usik', age: 25, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marina Volnova', age: 23, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrey Zamkovoy', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zou Shiming', age: 31, country: 'China', year: 2012, date: '12/08/2012', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Osmay Acosta', age: 23, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Georgiy Balakshin', age: 28, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carlos Banteux', age: 21, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Paddy Barnes', age: 21, country: 'Ireland', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Manus Boonjumnong', age: 28, country: 'Thailand', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roberto Cammarelle', age: 28, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rakhim Chakhkiyev', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emilio Correa Jr.', age: 22, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'James DeGale', age: 22, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Félix Díaz', age: 24, country: 'Dominican Republic', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Khédafi Djelkhir', age: 24, country: 'France', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kenny Egan', age: 26, country: 'Ireland', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Enkhbatyn Badar-Uugan', age: 23, country: 'Mongolia', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vaeceslav Gojan', age: 25, country: 'Moldova', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hanati Silamu', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yampier Hernández', age: 23, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "V'iacheslav Hlazkov", age: 23, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roniel Iglesias', age: 19, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sahin Imranov', age: 27, country: 'Azerbaijan', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hrachik Javakhyan', age: 24, country: 'Armenia', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tony Jeffries', age: 23, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Somjit Jongjohor', age: 33, country: 'Thailand', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bruno Julie', age: 30, country: 'Mauritius', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yakup Kiliç', age: 22, country: 'Turkey', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Jeong-Ju', age: 26, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andry Laffita', age: 30, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yankiel León', age: 26, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vasyl Lomachenko', age: 20, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vincenzo Picardi', age: 24, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Price', age: 25, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pürevdorjin Serdamba', age: 23, country: 'Mongolia', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Clemente Russo', age: 26, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bakhyt Sarsekbayev', age: 26, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yerkebulan Shynaliyev', age: 20, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vijender Singh', age: 22, country: 'India', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daouda Sow', age: 25, country: 'France', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Darren Sutherland', age: 26, country: 'Ireland', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Tishchenko', age: 24, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yordenis Ugás', age: 22, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alexis Vastine', age: 21, country: 'France', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Deontay Wilder', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhang Xiaoping', age: 26, country: 'China', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Zhilei', age: 25, country: 'China', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zou Shiming', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mohamed Aly', age: 29, country: 'Egypt', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lorenzo Aragon', age: 30, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Magomed Aripgadzhiyev', age: 26, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bakhtiyar Artayev', age: 21, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fuad Aslanov', age: 21, country: 'Azerbaijan', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yan Barthelemí', age: 24, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Manus Boonjumnong', age: 24, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roberto Cammarelle', age: 24, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andre Dirrell', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mohamed El-Sayed', age: 31, country: 'Egypt', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Naser El-Shami', age: 22, country: 'Syria', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuriorkis Gamboa', age: 22, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gaydarbek Gaydarbekov', age: 27, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Boris Georgiev', age: 21, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ionut Gheorghe', age: 20, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gennady Golovkin', age: 22, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ahmed Ismail', age: 28, country: 'Egypt', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jo Seok-Hwan', age: 24, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yudel Johnson', age: 23, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Kazakov', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Amir Khan', age: 17, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Utkirbek Khaydarov', age: 30, country: 'Uzbekistan', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Murat Khrachov', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Jeong-Ju', age: 22, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Song-Guk', age: 20, country: 'North Korea', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mario Kindelán', age: 33, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michel López', age: 27, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Agasi M?mm?dov', age: 24, country: 'Azerbaijan', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Worapoj Petchkoom', age: 23, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandr Povetkin', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Suriya Prasathinphimai', age: 24, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rustam Rahimov', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Guillermo Rigondeaux', age: 23, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Oleg Saitov', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Odlanier Solís', age: 24, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bakhodirdzhon Sultanov', age: 19, country: 'Uzbekistan', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vitali Tajbert', age: 22, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jérôme Thomas', age: 25, country: 'France', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Tishchenko', age: 20, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'André Ward', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Atagün Yalçinkaya', age: 17, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Serik Yeleuov', age: 23, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zou Shiming', age: 23, country: 'China', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Viktor Zuyev', age: 21, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mukhammad Kadyr Abdullayev', age: 26, country: 'Uzbekistan', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mohamed Allalou', age: 26, country: 'Algeria', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brahim Asloum', age: 21, country: 'France', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cristian Bejarano', age: 19, country: 'Mexico', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Vladimir Ch'ant'uria", age: 22, country: 'Georgia', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Serhiy Danylchenko', age: 26, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mukhtarkhan Dildabekov', age: 24, country: 'Kazakhstan', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Serhiy Dotsenko', age: 21, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kamil Dzhamaludinov', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zsolt Erdei', age: 26, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andriy Fedchuk', age: 20, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gaydarbek Gaydarbekov', age: 23, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vitalie Grusac', age: 23, country: 'Moldova', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jorge Gutiérrez', age: 25, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Audley Harrison', age: 28, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sultan-Akhmed Ibragimov', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yermakhan Ibraimov', age: 28, country: 'Kazakhstan', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ricardo Juarez', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Un-Chol', age: 20, country: 'North Korea', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mario Kindelán', age: 29, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sebastian Köber', age: 21, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andriy Kotelnyk', age: 22, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rudi Kraj', age: 22, country: 'Czech Republic', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandr Lebzyak', age: 31, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rafael Lozano', age: 30, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Diógenes Luña', age: 23, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Raimkul Malakhbekov', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandr Maletin', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Mikhaylov', age: 24, country: 'Uzbekistan', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wijan Ponlid', age: 24, country: 'Thailand', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Guillermo Rigondeaux', age: 19, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maikro Romero', age: 27, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rustam Saidov', age: 22, country: 'Uzbekistan', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oleg Saitov', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bekzat Sattarkhanov', age: 20, country: 'Kazakhstan', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Félix Savón', age: 32, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dorel Simion', age: 23, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marian Simion', age: 25, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Volodymyr Sydorenko', age: 23, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tahar Tamsamani', age: 20, country: 'Morocco', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jermain Taylor', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jérôme Thomas', age: 21, country: 'France', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pornchai Thongburan', age: 26, country: 'Thailand', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paolo Vidoz', age: 30, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Clarence Vinson', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ricardo Williams Jr.', age: 19, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bolat Zhumadilov', age: 27, country: 'Kazakhstan', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vüqar Mursal ?l?kb?rov', age: 19, country: 'Azerbaijan', year: 2000, date: '01/10/2000', sport: 'Boxing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Richy Adjei', age: 27, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'David Bissett', age: 30, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lascelles Brown', age: 35, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shelley-Ann Brown', age: 29, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Thomas Florschütz', age: 32, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steve Holcomb', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kaillie Humphries', age: 24, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris le Bihan', age: 32, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Steve Mesler', age: 31, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elana Meyers', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Heather Moyse', age: 31, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Justin Olsen', age: 22, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erin Pac', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Martin Putze', age: 25, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexander Rödiger', age: 24, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lyndon Rush', age: 29, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Curt Tomasevicz', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Helen Upperton', age: 30, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Voyevoda', age: 29, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Zubkov', age: 35, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lascelles Brown', age: 31, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valerie Fleming', age: 29, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cédric Grand', age: 30, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'René Hoppe', age: 29, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jennifer Isacco', age: 28, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thomas Lamparter', age: 27, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pierre Lueders', age: 35, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sandra Prokoff-Kiriasis', age: 31, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Martin Putze', age: 21, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shauna Rohbock', age: 28, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anja Schneiderheinze', age: 27, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Seliverstov', age: 29, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Voyevoda', age: 25, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gerda Weissensteiner', age: 37, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Filipp Yegorov', age: 27, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandr Zubkov', age: 31, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steve Anderhub', age: 31, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martin Annen', age: 28, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jill Bakken', age: 25, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carsten Embach', age: 33, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Susi Erdmann', age: 34, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vonetta Flowers', age: 28, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Todd Hays', age: 32, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Beat Hefti', age: 24, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nicole Herschmann', age: 26, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Garrett Hines', age: 32, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ulrike Holzner', age: 33, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Randy Jones', age: 32, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mike Kohn', age: 29, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Enrico Kühn', age: 24, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kevin Kuske', age: 23, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'André Lange', age: 28, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christoph Langen', age: 39, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sandra Prokoff-Kiriasis', age: 27, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christian Reich', age: 34, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bill Schuffenhauer', age: 28, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Doug Sharp', age: 32, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brian Shimer', age: 39, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dan Steele', age: 32, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Markus Zimmermann', age: 37, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Bobsleigh', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sandrine Bailly', age: 30, country: 'France', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sylvie Becaert', age: 34, country: 'France', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tora Berger', age: 28, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Bogaly-Titovets', age: 30, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tarjei Bø', age: 21, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ivan Cherezov', age: 29, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maksim Chudov', age: 27, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Darya Domracheva', age: 23, country: 'Belarus', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simon Eder', age: 27, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jakov Fak', age: 22, country: 'Croatia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Björn Ferry', age: 31, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Martin Fourcade', age: 21, country: 'France', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martina Glagow-Beck', age: 30, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Halvard Hanevold', age: 40, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrea Henkel', age: 32, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pavol Hurajt', age: 32, country: 'Slovakia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Khrustalyova', age: 29, country: 'Kazakhstan', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dominik Landertinger', age: 22, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniel Mesotitsch', age: 33, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Novikov', age: 30, country: 'Belarus', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olga Pylyova-Medvedtseva', age: 34, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anton Shipulin', age: 22, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Svetlana Sleptsova', age: 23, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kati Wilhelm', age: 33, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Frode Andresen', age: 32, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Katrin Apel', age: 32, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sandrine Bailly', age: 26, country: 'France', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sylvie Becaert', age: 30, country: 'France', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Bogaly-Titovets', age: 26, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ferréol Cannard', age: 27, country: 'France', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Chepikov', age: 39, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ivan Cherezov', age: 25, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Uschi Disl', age: 35, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ricco Groß', age: 35, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrea Henkel', age: 28, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikolay Kruglov', age: 24, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Delphine Peretto', age: 24, country: 'France', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Raphaël Poirée', age: 31, country: 'France', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Julien Robert', age: 31, country: 'France', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michael Rösch', age: 22, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pavel Rostovtsev', age: 34, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tomasz Sikora', age: 32, country: 'Poland', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liliya Yefremova', age: 28, country: 'Ukraine', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olga Zaytseva', age: 27, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Albina Akhatova', age: 25, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gunn Margit Andreassen', age: 28, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Frode Andresen', age: 28, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katrin Apel', age: 28, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vincent Defrasne', age: 24, country: 'France', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Egil Gjelland', age: 28, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Halvard Hanevold', age: 32, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Svetlana Ishmuratova', age: 29, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Galina Kukleva', age: 29, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gilles Marguet', age: 34, country: 'France', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Viktor Maygurov', age: 33, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Nikulchina', age: 27, country: 'Bulgaria', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wolfgang Perner', age: 34, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Julien Robert', age: 27, country: 'France', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Peter Sendel', age: 29, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ann Elen Skjelbreid', age: 30, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Linda Tjørhom', age: 22, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Julius Brink', age: 30, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alison Cerutti', age: 27, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Emanuel', age: 39, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juliana', age: 29, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jen Kessy', age: 34, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Larissa', age: 30, country: 'Brazil', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Misty May-Treanor', age: 34, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Martinš Plavinš', age: 27, country: 'Latvia', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jonas Reckermann', age: 33, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'April Ross', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Janis Šmedinš', age: 24, country: 'Latvia', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kerri Walsh', age: 33, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Phil Dalhausser', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emanuel', age: 35, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fábio', age: 29, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Márcio', age: 34, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Misty May-Treanor', age: 31, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ricardo', age: 33, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Todd Rogers', age: 34, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tian Jia', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kerri Walsh', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wang Jie', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Xue Chen', age: 19, country: 'China', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhang Xi', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adriana Behar', age: 35, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Javier Bosma', age: 34, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Emanuel', age: 31, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pablo Herrera', age: 22, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Patrick Heuscher', age: 27, country: 'Switzerland', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stefan Kobel', age: 30, country: 'Switzerland', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Misty May-Treanor', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Holly McPeak', age: 35, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ricardo', age: 29, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shelda', age: 31, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kerri Walsh', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elaine Youngs', age: 34, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jörg Ahmann', age: 34, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adriana Behar', age: 31, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dain Blanton', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Natalie Cook', age: 25, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eric Fonoimoana', age: 31, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Axel Hager', age: 31, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kerri-Ann Pottharst', age: 35, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ricardo', age: 25, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adriana Samuel', age: 34, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sandra', age: 27, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shelda', age: 27, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zé Marco', age: 29, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Beach Volleyball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carmelo Anthony', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Semyon Antonov', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Seimone Augustus', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Suzy Batkovic', age: 31, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Clémence Beikes', age: 28, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sue Bird', age: 31, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Abby Bishop', age: 23, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kobe Bryant', age: 33, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'José Manuel Calderón', age: 30, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liz Cambage', age: 20, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Swin Cash', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamika Catchings', age: 33, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tyson Chandler', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tina Charles', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Víctor Claver', age: 23, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anthony Davis', age: 19, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jennifer Digbeu', age: 25, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Céline Dumerc', age: 30, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kevin Durant', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rudy Fernández', age: 27, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sylvia Fowles', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vitaly Fridzon', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marc Gasol', age: 27, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pau Gasol', age: 32, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elodie Godin', age: 27, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Émilie Gomis', age: 28, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sandrine Gruda', age: 25, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'James Harden', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristi Harrower', age: 37, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Serge Ibaka', age: 22, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andre Iguodala', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lauren Jackson', age: 31, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'LeBron James', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rachel Jarry', age: 20, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Asjha Jones', age: 31, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sergey Karasyov', age: 18, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Kaun', age: 27, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Viktor Khryapa', age: 29, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dmitry Khvostov', age: 22, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrey Kirilenko', age: 31, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marion Laborde', age: 25, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Edwige Lawson-Wade', age: 33, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Florence Lepron', age: 27, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergio Llull', age: 24, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kevin Love', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kathleen MacLeod', age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Angel McCoughtry', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Endéné Miyem', age: 24, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Monya', age: 29, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maya Moore', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Timofey Mozgov', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Juan Carlos Navarro', age: 32, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Emmeline Ndongue', age: 29, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Jenna O'Hea", age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Candace Parker', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Paul', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anton Ponkrashov', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Felipe Reyes', age: 32, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Samantha Richards', age: 29, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergio Rodríguez', age: 26, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Víctor Sada', age: 28, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fernando San Emeterio', age: 28, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jenni Screen', age: 30, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Shved', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Belinda Snell', age: 31, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura Summerton-Hodges', age: 28, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Diana Taurasi', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeny Voronov', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Russell Westbrook', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lindsay Whalen', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Deron Williams', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Isabelle Yacoubou', age: 26, country: 'France', year: 2012, date: '12/08/2012', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Svetlana Abrosimova', age: 28, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carmelo Anthony', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Seimone Augustus', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Suzy Batkovic', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tully Bevilaqua', age: 36, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sue Bird', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carlos Boozer', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Bosh', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kobe Bryant', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'José Manuel Calderón', age: 26, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tamika Catchings', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rohanee Cox', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carlos Delfino', age: 25, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rudy Fernández', age: 23, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sylvia Fowles', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jorge Garbajosa', age: 30, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marc Gasol', age: 23, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pau Gasol', age: 28, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Manu Ginóbili', age: 31, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Román González', age: 30, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hollie Grima', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juan Pedro Gutiérrez', age: 24, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leonardo Gutiérrez', age: 30, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Becky Hammon', age: 31, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kristi Harrower', age: 33, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dwight Howard', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lauren Jackson', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'LeBron James', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carlos Jiménez', age: 32, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Federico Kammerichs', age: 28, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marina Karpunina', age: 24, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jason Kidd', age: 35, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ilona Korstin', age: 28, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marina Kuzina', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kara Lawson', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lisa Leslie', age: 36, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yekaterina Lisina', age: 20, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Raúl López', age: 28, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'DeLisha Milton-Jones', age: 33, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Álex Mumbrú', age: 29, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Juan Carlos Navarro', age: 28, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrés Nocioni', age: 28, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fabricio Oberto', age: 35, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Osipova', age: 27, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Candace Parker', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Paul', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erin Phillips', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cappie Pondexter', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antonio Porta', age: 24, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pablo Prigioni', age: 31, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tayshaun Prince', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paolo Quinteros', age: 29, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oksana Rakhmatulina', age: 31, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emma Randall', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Redd', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Felipe Reyes', age: 28, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Berni Rodríguez', age: 28, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ricky Rubio', age: 17, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luis Scola', age: 28, country: 'Argentina', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jenni Screen', age: 26, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tatyana Shchyegoleva', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Katie Smith', age: 34, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Belinda Snell', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Irina Sokolovskaya', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mariya Stepanova', age: 29, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura Summerton-Hodges', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Diana Taurasi', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Penny Taylor', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tina Thompson', age: 33, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nataliya Vodopyanova', age: 27, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dwyane Wade Jr.', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Deron Williams', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carmelo Anthony', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Arkhipova', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olga Arteshina', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Baranova', age: 32, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gianluca Basile', age: 29, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Suzy Batkovic', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sue Bird', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carlos Boozer', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sandy Brondello', age: 35, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Massimo Bulleri', age: 26, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Swin Cash', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamika Catchings', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roberto Chiacig', age: 29, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Allison Cook-Tranquilli', age: 32, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carlos Delfino', age: 21, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tim Duncan', age: 28, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Trish Fallon', age: 32, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gabriel Fernández', age: 27, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jack Galanda', age: 29, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luca Garri', age: 22, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Manu Ginóbili', age: 27, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yolanda Griffith', age: 34, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diana Gustilina', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leonardo Gutiérrez', age: 26, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristi Harrower', age: 29, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Walter Herrmann', age: 25, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Allen Iverson', age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lauren Jackson', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'LeBron James', age: 19, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Richard Jefferson', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shannon Johnson', age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariya Kalmykova', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Karpova', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ilona Korstin', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lisa Leslie', age: 32, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stephon Marbury', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Denis Marconato', age: 29, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shawn Marion', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michele Mian', age: 31, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alejandro Ariel Montecchia', age: 32, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrés Nocioni', age: 24, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fabricio Oberto', age: 31, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lamar Odom', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emeka Okafor', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Osipova', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Natalie Porter', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alicia Poto', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gianmarco Pozzecco', age: 31, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikola Radulovic', age: 31, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oksana Rakhmatulina', age: 27, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alex Righetti', age: 27, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ruth Riley', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rodolfo Rombaldoni', age: 27, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pepe Sánchez', age: 27, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luis Scola', age: 24, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hugo Ariel Sconochini', age: 33, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatyana Shchyegoleva', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Katie Smith', age: 30, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Belinda Snell', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Matteo Soragna', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rachael Sporn', age: 36, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dawn Staley', age: 34, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariya Stepanova', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Amar'e Stoudemire", age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura Summerton-Hodges', age: 20, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sheryl Swoopes', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diana Taurasi', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Penny Taylor', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tina Thompson', age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nataliya Vodopyanova', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dwyane Wade Jr.', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rubén Wolkowyski', age: 30, country: 'Argentina', year: 2004, date: '29/08/2004', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shareef Abdur-Rahim', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dainius Adomaitis', age: 26, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adriana', age: 29, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adrianinha', age: 21, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alessandra', age: 26, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ray Allen', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vin Baker', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jim Bilba', age: 32, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ruthie Bolton-Holifield', age: 33, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yann Bonato', age: 28, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carla Boyd', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michelle Brogan-Griffiths', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sandy Brondello', age: 32, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vince Carter', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cíntia', age: 25, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cláudinha', age: 25, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Makan Dioumassi', age: 28, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Teresa Edwards', age: 36, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gintaras Einikis', age: 30, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Trish Fallon', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laurent Foirest', age: 26, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Thierry Gadou', age: 31, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kevin Garnett', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrius Giedraitis', age: 27, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shelley Gorman-Sandie', age: 31, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yolanda Griffith', age: 30, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tim Hardaway', age: 34, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kristi Harrower', age: 25, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Helen', age: 27, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jo Hill', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Allan Houston', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lauren Jackson', age: 19, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Janeth', age: 31, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Šarunas Jasikevicius', age: 24, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cyril Julian', age: 26, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kelly', age: 20, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jason Kidd', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Annie La Fleur', age: 30, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lisa Leslie', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lilian', age: 21, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kestutis Marciulionis', age: 24, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tomas Masiulis', age: 24, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Darius Maskoliunas', age: 29, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikki McCray', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antonio McDyess', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'DeLisha Milton-Jones', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alonzo Mourning', age: 30, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Crawford Palmer', age: 30, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gary Payton', age: 32, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antoine Rigaudeau', age: 28, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stéphane Risacher', age: 28, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laurent Sciarra', age: 27, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Silvinha', age: 25, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ramunas Šiškauskas', age: 22, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Katie Smith', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Steve Smith', age: 31, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marta Sobral', age: 36, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Darius Songaila', age: 22, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Moustapha Sonko', age: 28, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rachael Sporn', age: 32, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dawn Staley', age: 30, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Saulius Štombergas', age: 26, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sheryl Swoopes', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mindaugas Timinskas', age: 26, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michele Timms', age: 35, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Frédéric Weis', age: 23, country: 'France', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jenny Whittle', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Natalie Williams', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kara Wolters', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zaine', age: 22, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eurelijus Žukauskas', age: 27, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Basketball', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mathias Boe', age: 32, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cai Yun', age: 32, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Long', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fu Haifeng', age: 28, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mizuki Fujii', age: 23, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jeong Jae-Seong', age: 29, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Reika Kakiiwa', age: 23, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Chong Wei', age: 29, country: 'Malaysia', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Yong-Dae', age: 23, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Xuerui', age: 21, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lin Dan', age: 28, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ma Jin', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carsten Mogensen', age: 29, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Saina Nehwal', age: 22, country: 'India', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joachim Fischer Nielsen', age: 33, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christinna Pedersen', age: 26, country: 'Denmark', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Valeriya Sorokina', age: 28, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tian Qing', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nina Vislova', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Yihan', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Xu Chen', age: 27, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhang Nan', age: 22, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cai Yun', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chen Jin', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Du Jing', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fu Haifeng', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'He Hanbin', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hwang Ji-Man', age: 24, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Markis Kido', age: 24, country: 'Indonesia', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lee Chong Wei', age: 25, country: 'Malaysia', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Gyeong-Won', age: 28, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Jae-Jin', age: 25, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lee Yong-Dae', age: 19, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lin Dan', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lilyana Natsir', age: 22, country: 'Indonesia', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hendra Setiawan', age: 23, country: 'Indonesia', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wei Yili', age: 26, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nova Widianto', age: 30, country: 'Indonesia', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Xie Xingfan', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maria Yulianti', age: 23, country: 'Indonesia', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhang Ning', age: 33, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Yawen', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gail Emms', age: 27, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hian Eng', age: 27, country: 'Indonesia', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jens Eriksen', age: 34, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ha Tae-Gwon', age: 29, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Taufik Hidayat', age: 23, country: 'Indonesia', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Huang Sui', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim Dong-Mun', age: 28, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sony Dwi Kuncoro', age: 20, country: 'Indonesia', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lee Dong-Su', age: 30, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Gyeong-Won', age: 24, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Flandy Limpele', age: 30, country: 'Indonesia', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mia Audina', age: 24, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Na Gyeong-Min', age: 27, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nathan Robertson', age: 27, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mette Schjoldager', age: 27, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Son Seung-Mo', age: 24, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yang Wei', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yu Yong-Seong', age: 29, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhang Jiewen', age: 23, country: 'China', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Jun', age: 26, country: 'China', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Ning', age: 29, country: 'China', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhou Mi', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simon Archer', age: 27, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ge Fei', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gong Zhichao', age: 23, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gu Jun', age: 25, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tony Gunawan', age: 25, country: 'Indonesia', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ha Tae-Gwon', age: 25, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Trikus Haryanto', age: 26, country: 'Indonesia', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hendrawan', age: 28, country: 'Indonesia', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Huang Nanyan', age: 23, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ji Xinpeng', age: 22, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Dong-Mun', age: 24, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lee Dong-Su', age: 26, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Camilla Martin', age: 26, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Qin Yiyuan', age: 27, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Minarti Timur', age: 32, country: 'Indonesia', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Candra Wijaya', age: 25, country: 'Indonesia', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Joanne Wright-Goode', age: 27, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xia Xuanze', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yang Wei', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ye Zhaoying', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yu Yong-Seong', age: 25, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhang Jun', age: 22, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Valerie Adams-Vili', age: 27, country: 'New Zealand', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Habiba Al-Ghribi-Boudra', age: 28, country: 'Tunisia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ade Alleyne-Forte', age: 23, country: 'Trinidad and Tobago', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nijel Amos', age: 18, country: 'Botswana', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sofia Assefa', age: 24, country: 'Ethiopia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ryan Bailey', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kemar Bailey-Cole', age: 20, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Keshia Baker', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brigetta Barrett', age: 21, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Erick Barrondo', age: 21, country: 'Guatemala', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mutaz Essa Barshim', age: 21, country: 'Qatar', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tariku Bekele', age: 25, country: 'Ethiopia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Keston Bledman', age: 24, country: 'Trinidad and Tobago', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chris Brown', age: 33, country: 'Bahamas', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yelyzaveta Bryzhina', age: 22, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gamze Bulut', age: 20, country: 'Turkey', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marc Burns', age: 29, country: 'Trinidad and Tobago', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Asli Çakir', age: 26, country: 'Turkey', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Emmanuel Callender', age: 28, country: 'Trinidad and Tobago', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Schillonie Calvert', age: 24, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nesta Carter', age: 26, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Ding', age: 19, country: 'China', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatyana Chernova', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Chicherova', age: 30, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Javier Culson', age: 28, country: 'Puerto Rico', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christine Day', age: 25, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Meseret Defar', age: 28, country: 'Ethiopia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Janay DeLoach', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeff Demps', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lashinda Demus', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Diamond Dixon', age: 20, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fabrizio Donato', age: 35, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Derek Drouin', age: 22, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ashton Eaton', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jessica Ennis', age: 26, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatyana Firova', age: 29, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Frater', age: 29, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tyson Gay', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dejen Gebremeskel', age: 22, country: 'Ethiopia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tiki Gelana', age: 24, country: 'Ethiopia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gong Lijiao', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robbie Grabarz', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuliya Gushchina', age: 29, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ehsan Haddadi', age: 27, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Trey Hardee', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dawn Harper', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Robert Harting', age: 27, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Betty Heidler', age: 28, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zuzana Hejnová', age: 25, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Samantha Henry-Robinson', age: 23, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Reese Hoffa', age: 34, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Raphael Holzdeppe', age: 22, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Caterine Ibargüén', age: 28, country: 'Colombia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Abdalaati Iguider', age: 25, country: 'Morocco', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Isinbayeva', age: 30, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maryam Jamal', age: 27, country: 'Bahrain', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kirani James', age: 19, country: 'Grenada', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Priscah Jeptoo', age: 28, country: 'Kenya', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olga Kaniskina', age: 27, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gerd Kanter', age: 33, country: 'Estonia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anastasiya Kapachinskaya', age: 32, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ezekiel Kemboi', age: 30, country: 'Kenya', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Trell Kimmons', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stephen Kiprotich', age: 23, country: 'Uganda', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wilson Kipsang Kiprotich', age: 30, country: 'Kenya', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sally Jepkosgei Kipyego', age: 26, country: 'Kenya', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Kirdyapkin', age: 32, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Abel Kirui', age: 30, country: 'Kenya', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Timothy Kitum', age: 17, country: 'Kenya', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bianca Knight', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeniya Kolodko', age: 22, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Primož Kozmus', age: 32, country: 'Slovenia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Antonina Krivoshapka', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Erik Kynard', age: 21, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Lashmanova', age: 20, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Renaud Lavillenie', age: 25, country: 'France', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Deon Lendore', age: 19, country: 'Trinidad and Tobago', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Yanfeng', age: 33, country: 'China', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shereefa Lloyd', age: 29, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Thomas Longosiwa', age: 30, country: 'Kenya', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatyana Lysenko', age: 28, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tianna Madison', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tomasz Majewski', age: 30, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Taoufik Makhloufi', age: 24, country: 'Algeria', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Josh Mance', age: 20, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Leo Manzano', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Mathieu', age: 28, country: 'Bahamas', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Francena McCorory', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sally McLellan-Pearson', age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tony McQuay', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mahiedine Mekhissi-Benabbad', age: 27, country: 'France', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aries Merritt', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ramon Miller', age: 25, country: 'Bahamas', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Manteo Mitchell', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Koji Murofushi', age: 37, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Abel Mutai', age: 23, country: 'Kenya', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Nazarova', age: 33, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bryshon Nellum', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christina Obergföll', age: 30, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christine Ohuruogu', age: 28, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Björn Otto', age: 34, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Oleksandr P'iatnytsia", age: 27, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hansle Parchment', age: 22, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Krisztián Pars', age: 30, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Darvis Patton', age: 34, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sandra Perkovic', age: 22, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatyana Petrova-Arkhipova', age: 29, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Demetrius Pinder', age: 23, country: 'Bahamas', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Darya Pishchalnikova', age: 27, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yekaterina Poistogova', age: 21, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olesia Povkh', age: 24, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Qieyang Shenjie', age: 21, country: 'China', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brittney Reese', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jason Richardson', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Riemien', age: 25, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Rudisha', age: 23, country: 'Kenya', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Galen Rupp', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Greg Rutherford', age: 25, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antti Ruuskanen', age: 28, country: 'Finland', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olga Rypakova', age: 27, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olha Saladukha', age: 29, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Félix Sánchez', age: 34, country: 'Dominican Republic', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Luguelín Santos', age: 19, country: 'Dominican Republic', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Savinova', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lilli Schwarzkopf', age: 28, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Caster Semenya', age: 21, country: 'South Africa', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Svetlana Shkolina', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Si Tianfeng', age: 28, country: 'China', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yarisley Silva', age: 25, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sherone Simpson', age: 27, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Sokolova', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jarrin Solomon', age: 26, country: 'Trinidad and Tobago', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Barbora Špotáková', age: 31, country: 'Czech Republic', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Linda Stahl', age: 26, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kerron Stewart', age: 28, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'David Storl', age: 22, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jenn Stuczynski-Suhr', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hrystyna Stuy', age: 24, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Leonel Suárez', age: 24, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jared Tallent', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jeneba Tarmoh', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Angelo Taylor', age: 33, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christian Taylor', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Richard Thompson', age: 27, country: 'Trinidad and Tobago', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michael Tinsley', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ivan Ukhov', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Keshorn Walcott', age: 19, country: 'Trinidad and Tobago', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wang Zhen', age: 20, country: 'China', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mitch Watt', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Warren Weir', age: 22, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kellie Wells', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rosemarie Whyte', age: 25, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lauryn Williams', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shericka Williams', age: 26, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Novlene Williams-Mills', age: 30, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anita Wlodarczyk', age: 27, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuliya Zaripova', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariya Abakumova', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valerie Adams-Vili', age: 23, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Virgilijus Alekna', age: 36, country: 'Lithuania', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Denis Alekseyev', age: 20, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olena Antonova', age: 36, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aaron Armstrong', age: 30, country: 'Trinidad and Tobago', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nobuharu Asahara', age: 36, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mehdi Baala', age: 29, country: 'France', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dretti Bain', age: 22, country: 'Bahamas', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yarelis Barrios', age: 25, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hasna Benhassi', age: 30, country: 'Morocco', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Keston Bledman', age: 20, country: 'Trinidad and Tobago', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valeriy Borchin', age: 21, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olivia Borlée', age: 22, country: 'Belgium', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chris Brown', age: 29, country: 'Bahamas', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stephanie Brown-Trafton', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wilfred Bungei', age: 28, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marc Burns', age: 25, country: 'Trinidad and Tobago', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Emmanuel Callender', age: 24, country: 'Trinidad and Tobago', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ibrahim Camejo', age: 26, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Veronica Campbell-Brown', age: 26, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Christian Cantwell', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nesta Carter', age: 22, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yuliya Chermoshanskaya', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatyana Chernova', age: 20, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Chicherova', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bryan Clay', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shawn Crawford', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tasha Danvers', age: 30, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Meseret Defar', age: 24, country: 'Ethiopia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pigi Devetzi', age: 32, country: 'Greece', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vadim Devyatovsky', age: 31, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Constantina Dita-Tomescu', age: 38, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nataliya Dobrynska', age: 26, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maksim Dyldin', age: 21, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nelson Évora', age: 24, country: 'Portugal', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandra Fedoriva', age: 19, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Svetlana Feofanova', age: 28, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatyana Firova', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shalane Flanagan', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hyleas Fountain', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shelly-Ann Fraser-Pryce', age: 21, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michael Frater', age: 25, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vladislav Frolov', age: 28, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Gevaert', age: 30, country: 'Belgium', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jaouad Gharib', age: 36, country: 'Morocco', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dawn Harper', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Natasha Hastings', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tia Hellebaut', age: 30, country: 'Belgium', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Monique Henderson', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Steve Hooker', age: 26, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Franca Idoko', age: 23, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Phillips Idowu', age: 29, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Isinbayeva', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ismail Ahmed Ismail', age: 23, country: 'Sudan', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Halimat Ismaila', age: 24, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bershawn Jackson', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pamela Jelimo', age: 18, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eunice Jepkorir', age: 26, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Janeth Jepkosgei', age: 24, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sheena Johnson-Tosta', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olga Kaniskina', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gerd Kanter', age: 29, country: 'Estonia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anastasiya Kapachinskaya', age: 28, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tsegaye Kebede', age: 21, country: 'Ethiopia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gloria Kemasoude', age: 28, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Khoronenko-Mikhnevich', age: 26, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eliud Kipchoge', age: 23, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Asbel Kiprop', age: 19, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brimin Kipruto', age: 23, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Micah Kogo', age: 22, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anton Kokorin', age: 21, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ainars Kovals', age: 26, country: 'Latvia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Primož Kozmus', age: 28, country: 'Slovenia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Kravchenko', age: 22, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nancy Langat', age: 26, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Iryna Lishchynska', age: 32, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lyudmila Litvinova', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shereefa Lloyd', age: 25, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Priscilla Lopes-Schliep', age: 25, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yevgeniy Lukyanenko', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maurren Maggi', age: 32, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tomasz Majewski', age: 26, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hanna Mariën', age: 26, country: 'Belgium', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Germaine Mason', age: 25, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Richard Mateelong', age: 24, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michael Mathieu', age: 24, country: 'Bahamas', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Piotr Malachowski', age: 25, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Françoise Mbango', age: 32, country: 'Cameroon', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sally McLellan-Pearson', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mahiedine Mekhissi-Benabbad', age: 23, country: 'France', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oksana Menkova', age: 26, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yelena Migunova', age: 24, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrey Mikhnevich', age: 32, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ramon Miller', age: 21, country: 'Bahamas', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Godfrey Khotso Mokoena', age: 23, country: 'South Africa', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Avard Moncur', age: 29, country: 'Bahamas', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yipsi Moreno', age: 27, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Catherine Ndereba', age: 36, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Denis Nizhegorodov', age: 28, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christina Obergföll', age: 26, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christine Ohuruogu', age: 24, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Blessing Okagbare', age: 19, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'David Oliver', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Damola Osayomi', age: 22, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Agnes Osazuwa', age: 19, country: 'Nigeria', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nadezhda Ostapchuk', age: 27, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Élodie Ouédraogo', age: 27, country: 'Belgium', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'David Payne', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jefferson Pérez', age: 34, country: 'Ecuador', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tero Pitkämäki', age: 25, country: 'Finland', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yevgeniya Polyakova', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Asafa Powell', age: 25, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elisa Rigaudo', age: 28, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dayron Robles', age: 21, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yaroslav Rybakov', age: 27, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irving Saladino', age: 25, country: 'Panama', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gulnara Samitova-Galkina', age: 30, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Leevan Sands', age: 27, country: 'Bahamas', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alex Schwazer', age: 23, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sileshi Sihine', age: 25, country: 'Ethiopia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrey Silnov', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sherone Simpson', age: 24, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Edwin Soi', age: 22, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Barbora Špotáková', age: 27, country: 'Czech Republic', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jenn Stuczynski-Suhr', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Leonel Suárez', age: 20, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shingo Suetsugu', age: 28, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Shinji Takahira', age: 24, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dwight Thomas', age: 27, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andreas Thorkildsen', age: 26, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ivan Tikhon', age: 32, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Tobias', age: 27, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Naoki Tsukahara', age: 23, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kjersti Tysse-Plätzer', age: 36, country: 'Norway', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tatyana Veshkurova', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Blanka Vlašic', age: 24, country: 'Croatia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yekaterina Volkova', age: 30, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Melaine Walker', age: 25, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sammy Wanjiru', age: 21, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rosemarie Whyte', age: 21, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bobby-Gaye Wilkins', age: 19, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrae Williams', age: 25, country: 'Bahamas', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Novlene Williams-Mills', age: 26, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nick Willis', age: 25, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mary Wineberg', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Regi Witherspoon', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alfred Kirwa Yego', age: 21, country: 'Kenya', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Denys Yurchenko', age: 30, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhang Wenxiu', age: 32, country: 'China', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zhou Chunxiu', age: 29, country: 'China', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Virgilijus Alekna', age: 32, country: 'Lithuania', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Deji Aliu', age: 28, country: 'Nigeria', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Esref Apak', age: 22, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christine Arron', age: 30, country: 'France', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Musa Audu', age: 24, country: 'Nigeria', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jaroslav Bába', age: 19, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleen Bailey', age: 23, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Stefano Baldini', age: 33, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hasna Benhassi', age: 26, country: 'Morocco', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuriy Bilonoh', age: 30, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yury Borzakovsky', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ivano Brugnetti', age: 27, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michelle Burgher', age: 27, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniil Burkenya', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Darren Campbell', age: 30, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jolanda Ceplak', age: 27, country: 'Slovenia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maria Cioncan', age: 27, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bryan Clay', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Crystal Cox', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yunaika Crawford', age: 21, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yumileidi Cumbá', age: 29, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nadia Davy', age: 23, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vanderlei de Lima', age: 35, country: 'Brazil', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nathan Deakes', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Meseret Defar', age: 20, country: 'Ethiopia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pigi Devetzi', age: 28, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marlon Devonish', age: 28, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ejegayehu Dibaba', age: 22, country: 'Ethiopia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tirunesh Dibaba', age: 19, country: 'Ethiopia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Deena Drossin-Kastor', age: 31, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pat Dwyer', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aaron Egbele', age: 25, country: 'Nigeria', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Uchenna Emedolu', age: 27, country: 'Nigeria', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olusoji Fasuba', age: 20, country: 'Nigeria', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Allyson Felix', age: 18, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sylviane Félix', age: 26, country: 'France', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Svetlana Feofanova', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Debbie Ferguson-McKenzie', age: 28, country: 'Bahamas', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Francisco Javier Fernández', age: 27, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tatyana Firova', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olga Fyodorova', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anier García', age: 28, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jason Gardener', age: 28, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Giuseppe Gibilisco', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ana Guevara', age: 27, country: 'Mexico', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joanna Hayes', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Matt Hemingway', age: 31, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Monique Henderson', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Monique Hennagan', age: 28, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Clinton Hill', age: 24, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stefan Holm', age: 28, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Muriel Hurtis-Houairi', age: 25, country: 'France', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Isinbayeva', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nataliya Ivanova', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olimpiada Ivanova', age: 33, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Godday James', age: 20, country: 'Nigeria', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dmitry Karpov', age: 23, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Meb Keflezighi', age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Naman Keïta', age: 26, country: 'France', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anastasia Kelesidou', age: 31, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ezekiel Kemboi', age: 22, country: 'Kenya', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irina Khabarova', age: 38, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fani Khalkia', age: 25, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eliud Kipchoge', age: 19, country: 'Kenya', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wilson Kipketer', age: 33, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brimin Kipruto', age: 19, country: 'Kenya', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nadine Kleinert-Schmitt', age: 28, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carolina Klüft', age: 21, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paul Kipsiele Koech', age: 22, country: 'Kenya', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robert Korzeniowski', age: 36, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatyana Kotova', age: 27, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zoltán Kovágó', age: 25, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olesya Krasnomovets', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Svetlana Krivelyova', age: 35, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Larisa Kruglova', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olga Kuzenkova', age: 33, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bernard Lagat', age: 29, country: 'Kenya', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tayna Lawrence', age: 28, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Lewis-Francis', age: 21, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Liu Xiang', age: 21, country: 'China', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tim Mack', age: 31, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sergey Makarov', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Véronique Mang', age: 19, country: 'France', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mirela Maniani-Tzelili', age: 27, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joan Lino Martínez', age: 26, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Françoise Mbango', age: 28, country: 'Cameroon', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Beverly McDonald', age: 34, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Danny McFarlane', age: 32, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Osleidys Menéndez', age: 24, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Coby Miller', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'John Moffitt', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yipsi Moreno', age: 23, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Melissa Morrison', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mbulaeni Mulaudzi', age: 23, country: 'South Africa', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Koji Murofushi', age: 29, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nataliya Nazarova', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Catherine Ndereba', age: 32, country: 'Kenya', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adam Nelson', age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steffi Nerius', age: 32, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuliya Nesterenko', age: 25, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Denis Nizhegorodov', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mizuki Noguchi', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Francis Obikwelu', age: 25, country: 'Portugal', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Isabella Ochichi', age: 24, country: 'Kenya', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joachim Olsen', age: 27, country: 'Denmark', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christian Olsson', age: 24, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marian Oprea', age: 22, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mark Ormrod', age: 21, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olena Ovcharova-Krasovska', age: 28, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Darvis Patton', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dwight Phillips', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sandie Richards', age: 35, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sanya Richards-Ross', age: 19, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Moushaumi Robinson', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrew Rock', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Rogowska', age: 23, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Sadova', age: 32, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Félix Sánchez', age: 26, country: 'Dominican Republic', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jane Saville', age: 29, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roman Šebrle', age: 29, country: 'Czech Republic', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sileshi Sihine', age: 21, country: 'Ethiopia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rui Silva', age: 27, country: 'Portugal', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Simagina', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sherone Simpson', age: 20, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Austra Skujyte', age: 25, country: 'Lithuania', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Slesarenko', age: 22, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ronetta Smith', age: 24, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kelly Sotherton', age: 27, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'John Steffensen', age: 21, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Toby Stevenson', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vita Stopina', age: 28, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hestrie Storbeck-Cloete', age: 26, country: 'South Africa', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuliya Tabakova', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zersenay Tadesse', age: 22, country: 'Eritrea', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksander Tammert', age: 31, country: 'Estonia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ionela Târlea-Manolache', age: 28, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tetiana Tereshchuk-Antypova', age: 34, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreas Thorkildsen', age: 22, country: 'Norway', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ivan Tikhon', age: 28, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tatyana Tomashova', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Terrence Trammell', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'DeeDee Trotter', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Athanasia Tsoumeleka', age: 22, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Derartu Tulu', age: 32, country: 'Ethiopia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Enefiok Udo-Obong', age: 22, country: 'Nigeria', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vadims Vasilevskis', age: 22, country: 'Latvia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Voyevodin', age: 34, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Saul Weigopwa', age: 18, country: 'Nigeria', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bernard Williams III', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lauryn Williams', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tonique Williams-Darling', age: 28, country: 'Bahamas', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Novlene Williams-Mills', age: 22, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Darold Williamson', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kelly Willie', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Xing Huina', age: 20, country: 'China', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irina Yatchenko', age: 38, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olesya Zykina', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gezahgne Abera', age: 22, country: 'Ethiopia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Hadi Soua'an Al-Somaily", age: 23, country: 'Saudi Arabia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Virgilijus Alekna', age: 28, country: 'Lithuania', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Glory Alozie', age: 22, country: 'Nigeria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrea Anderson', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vladimir Andreyev', age: 34, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Igor Astapkovich', age: 37, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nduka Awazie', age: 19, country: 'Nigeria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sanjay Ayre', age: 20, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steve Backley', age: 31, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sunday Bada', age: 31, country: 'Nigeria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Violeta Beclea-Szekely', age: 35, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kajsa Bergqvist', age: 23, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nezha Bidouane', age: 31, country: 'Morocco', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michael Blackwood', age: 22, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wilson Boit Kipketer', age: 26, country: 'Kenya', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kenny Brokenburr', age: 31, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Brown', age: 21, country: 'Bahamas', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michelle Burgher', age: 23, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Darren Campbell', age: 27, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Veronica Campbell-Brown', age: 18, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'José A. César', age: 22, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joyce Chepchumba', age: 29, country: 'Kenya', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Clement Chukwu', age: 27, country: 'Nigeria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eldece Clarke-Lewis', age: 35, country: 'Bahamas', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'LaTasha Colander-Richardson', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mark Crear', age: 31, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'André da Silva', age: 27, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Claudinei da Silva', age: 29, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stacy Dragila', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Heike Drechsler', age: 35, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jon Drummond', age: 32, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jonathan Edwards', age: 34, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Torri Edwards', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hicham El Guerrouj', age: 26, country: 'Morocco', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ali Ezzine', age: 22, country: 'Morocco', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aigars Fadejevs', age: 24, country: 'Latvia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Debbie Ferguson-McKenzie', age: 24, country: 'Bahamas', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vala Flosadóttir', age: 22, country: 'Iceland', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Merlene Frazer', age: 26, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cathy Freeman', age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sevatheda Fynes', age: 25, country: 'Bahamas', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fidelis Gadzama', age: 20, country: 'Nigeria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chryste Gaines', age: 30, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anier García', age: 24, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Iván García', age: 28, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yoel García', age: 26, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Haile Gebrselassie', age: 27, country: 'Ethiopia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'John Godina', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Svetlana Goncharenko', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Steffi Graf', age: 27, country: 'Austria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tatiana Grigorieva', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Abderrahmane Hammad', age: 23, country: 'Algeria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Arsi Harju', age: 26, country: 'Finland', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alvin Harrison', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Monique Hennagan', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Llewellyn Herbert', age: 23, country: 'South Africa', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Noé Hernández', age: 21, country: 'Mexico', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kelly Holmes', age: 30, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olena Hovorova', age: 27, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Charmaine Howell', age: 25, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chris Huffins', age: 30, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nick Hysong', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Susanthika Jayasinghe', age: 24, country: 'Sri Lanka', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lawrence Johnson', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Johnson', age: 33, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marion Jones', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Denis Kapustin', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anastasia Kelesidou', age: 27, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kostas Kenteris', age: 27, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wilson Kipketer', age: 29, country: 'Denmark', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Klyugin', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Reuben Kosgei', age: 21, country: 'Kenya', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olga Kotlyarova', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatyana Kotova', age: 23, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Frantz Kruger', age: 25, country: 'South Africa', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Astrid Kumbernuss', age: 30, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olga Kuzenkova', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bernard Lagat', age: 25, country: 'Kenya', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brahim Lahlafi', age: 32, country: 'Morocco', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatyana Lebedeva', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Brian Lewis', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Denise Lewis', age: 28, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vicente Lima', age: 23, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sergey Makarov', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mirela Maniani-Tzelili', age: 23, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tereza Marinova', age: 23, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Fiona May', age: 30, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Freddy Mayola', age: 22, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Michael McDonald', age: 25, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Danny McFarlane', age: 28, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Troy McIntosh', age: 27, country: 'Bahamas', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Osleidys Menéndez', age: 20, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Noria Mérah-Benida', age: 29, country: 'Algeria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katharine Merry', age: 26, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Assefa Mezegebu', age: 22, country: 'Ethiopia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jearl Miles-Clark', age: 34, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Avard Moncur', age: 21, country: 'Bahamas', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tim Montgomery', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jude Monye', age: 26, country: 'Nigeria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Melissa Morrison', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kirsten Münchow', age: 23, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tim Munnings', age: 34, country: 'Bahamas', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oana Musunoi-Pantelimon', age: 28, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maria Mutola', age: 27, country: 'Mozambique', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nataliya Nazarova', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Adam Nelson', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Noah Ngeny', age: 21, country: 'Kenya', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Erki Nool', age: 30, country: 'Estonia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Sonia O'Sullivan", age: 30, country: 'Ireland', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carl Oliver', age: 31, country: 'Bahamas', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iván Pedroso', age: 27, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Larisa Peleshenko', age: 36, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Luis Alberto Pérez', age: 31, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nanceen Perry', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Catherine Pomales-Scott', age: 27, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yelena Prokhorova', age: 22, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yanina Provalinskaya-Karolchik', age: 23, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Edson Ribeiro', age: 27, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fernanda Ribeiro', age: 31, country: 'Portugal', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sandie Richards', age: 31, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Passion Richardson', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lars Riedel', age: 33, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Djabir Saïd-Guerni', age: 23, country: 'Algeria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ali Saïdi-Sief', age: 22, country: 'Algeria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Joel Sánchez', age: 36, country: 'Mexico', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Natasha Sazanovich', age: 27, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nils Schumann', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roman Šebrle', age: 25, country: 'Czech Republic', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roman Shchurenko', age: 24, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olga Shishigina', age: 31, country: 'Kazakhstan', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lidia Simon', age: 27, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kamila Skolimowska', age: 17, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Trine Solberg-Hattestad', age: 34, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yuliya Sotnikova', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Javier Sotomayor', age: 32, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Cláudio Sousa', age: 26, country: 'Brazil', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hestrie Storbeck-Cloete', age: 22, country: 'South Africa', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chandra Sturrup', age: 29, country: 'Bahamas', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Naoko Takahashi', age: 28, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maksim Tarasov', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jai Taurima', age: 28, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Angelo Taylor', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Paul Tergat', age: 31, country: 'Kenya', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aikaterini Thanou', age: 25, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Obadele Thompson', age: 24, country: 'Barbados', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tesfaye Tola', age: 25, country: 'Ethiopia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Terrence Trammell', age: 21, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Derartu Tulu', age: 28, country: 'Ethiopia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kjersti Tysse-Plätzer', age: 28, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Enefiok Udo-Obong', age: 18, country: 'Nigeria', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'María Vascó', age: 24, country: 'Spain', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nicola Vizzoni', age: 26, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eric Wainaina', age: 26, country: 'Kenya', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Liping', age: 24, country: 'China', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bernard Williams III', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chris Williams', age: 28, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Million Wolde', age: 21, country: 'Ethiopia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irina Yatchenko', age: 34, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Yelesina', age: 30, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jan Železný', age: 34, country: 'Czech Republic', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Szymon Ziólkowski', age: 24, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ellina Zvereva', age: 39, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Olesya Zykina', age: 19, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Didier Défago', age: 32, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrea Fischbacher', age: 24, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Carlo Janka', age: 23, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kjetil Jansrud', age: 24, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'André Myhrer', age: 27, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anja Pärson', age: 28, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giuliano Razzoli', age: 25, country: 'Italy', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Viktoria Rebensburg', age: 20, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marlies Schild', age: 28, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrew Weibrecht', age: 24, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Šárka Záhrobská', age: 25, country: 'Czech Republic', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Silvan Zurbriggen', age: 28, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kjetil André Aamodt', age: 34, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Joël Chenal', age: 32, country: 'France', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Antoine Dénériaz', age: 29, country: 'France', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Reinfried Herbst', age: 27, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ambrosi Hoffmann', age: 28, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nicole Hosp', age: 22, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bruno Kernen', age: 33, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ivica Kostelic', age: 26, country: 'Croatia', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ted Ligety', age: 21, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Julia Mancuso', age: 21, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alexandra Meissnitzer', age: 32, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Ottosson', age: 29, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tanja Poutiainen', age: 25, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martina Schild', age: 24, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michael Walchhofer', age: 30, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sébastien Amiez', age: 29, country: 'France', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniela Ceccarelli', age: 26, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Martina Ertl-Renz', age: 28, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Isolde Kostner', age: 26, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carole Montillet-Carles', age: 28, country: 'France', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sonja Nef', age: 29, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laure Pequegnot', age: 26, country: 'France', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Karen Putzer', age: 23, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andreas Schifferer', age: 27, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Fritz Strobl', age: 29, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jean-Pierre Vidal', age: 24, country: 'France', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariana Avitia', age: 18, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cheng Ming', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Choi Hyeon-Ju', age: 27, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dai Xiaoxiang', age: 21, country: 'China', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Brady Ellison', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Fang Yuting', age: 22, country: 'China', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Michele Frangilli', age: 36, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Takaharu Furukawa', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Marco Galiazzo', age: 29, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ren Hayakawa', age: 24, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Im Dong-Hyeon', age: 27, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jake Kaminski', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Miki Kanie', age: 23, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kaori Kawanaka', age: 20, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Bub-Min', age: 21, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lee Seong-Jin', age: 27, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mauro Nespoli', age: 24, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aída Román', age: 24, country: 'Mexico', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jacob Wukie', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Xu Jing', age: 21, country: 'China', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Virginie Arnold', age: 28, country: 'France', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bair Badyonov', age: 32, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chen Ling', age: 21, country: 'China', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ilario Di Buò', age: 51, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sophie Dodémont', age: 34, country: 'France', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marco Galiazzo', age: 25, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Guo Dan', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Im Dong-Hyeon', age: 23, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jiang Lin', age: 26, country: 'China', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Joo Hyun-Jung', age: 26, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lee Chang-Hwan', age: 26, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Li Wenquan', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mauro Nespoli', age: 20, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Viktor Ruban', age: 27, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bérengère Schuh', age: 24, country: 'France', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xue Haifeng', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chen Li-Ju', age: 23, country: 'Chinese Taipei', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chen Szu-Yuan', age: 23, country: 'Chinese Taipei', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tim Cuddihy', age: 17, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marco Galiazzo', age: 21, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'He Ying', age: 27, country: 'China', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dmytro Hrachov', age: 20, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Im Dong-Hyeon', age: 19, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jang Yong-Ho', age: 28, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lin Sang', age: 26, country: 'China', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liu Ming-Huang', age: 19, country: 'Chinese Taipei', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Park Gyeong-Mo', age: 28, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Viktor Ruban', age: 23, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Oleksandr Serdiuk', age: 26, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Cheng-Pang', age: 17, country: 'Chinese Taipei', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alison Williamson', age: 32, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wu Hui-Ju', age: 21, country: 'Chinese Taipei', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hiroshi Yamamoto', age: 41, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuan Shu-Chi', age: 19, country: 'Chinese Taipei', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yun Mi-Jin', age: 21, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Juanjuan', age: 23, country: 'China', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Matteo Bisiani', age: 24, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nataliya Burdeina', age: 26, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ilario Di Buò', age: 43, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Simon Fairweather', age: 30, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Michele Frangilli', age: 24, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jang Yong-Ho', age: 24, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Butch Johnson', age: 45, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Cheong-Tae', age: 20, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Barbara Mensing', age: 39, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'O Gyo-Mun', age: 28, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cornelia Pfohl', age: 29, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Olena Sadovnycha', age: 32, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kateryna Serdiuk', age: 17, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wietse van Alten', age: 21, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sandra Wagner-Sachse', age: 31, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rod White', age: 23, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 0, bronze: 1, total: 1, }, ]; ``` ```ts import {AdaptableReadyInfo} from '@adaptabletools/adaptable'; import {IOlympicData, getRowData} from './rowData'; export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => { adaptableApi.gridApi.addGridData( getRowData().filter(row => ['Athletics', 'Basketball', 'Swimming'].includes(row.sport) ) ); }; ``` ## Pivot Column Total Pivot Column Totals are **subtotal** columns inserted for each Pivot Column Group. AdapTable calculates each group-specific total using a common aggregation function. All Aggregation Columns must use the **same** `aggFunc` (e.g. `sum` ) **Example: Pivot Column Totals** Pivot Column Totals - Like the demo above, this example also includes 2 Layouts which each contain aggregations for the Gold, Silver and Bronze columns - Both Layouts are configured to display Pivot Column Totals - in one Layout the columns are placed at the start of each Group, and in the other Layout at the end - Note: a Pivot Column Total is displayed for each Pivot Column Grouping, e.g. for `Athletics`, `Athletics/2000`, `Athletics/2004`, `Basketball`, `Basketball/2000` etc. ```ts import {AdaptableOptions} from '@adaptabletools/adaptable'; import {IOlympicData} from './rowData'; export const adaptableOptions: AdaptableOptions = { primaryKey: 'athlete', adaptableId: 'Pivot Column Total', initialState: { Dashboard: { Tabs: [{Name: 'Demo', Toolbars: ['Layout']}], }, StatusBar: { StatusBars: [ { Key: 'Center Panel', StatusBarPanels: ['Layout'], }, ], }, Theme: {CurrentTheme: 'dark'}, Layout: { CurrentLayout: 'Group Total Before', Layouts: [ { Name: 'Group Total Before', PivotColumns: ['sport', 'year'], PivotGroupedColumns: ['country'], PivotColumnTotal: 'before', PivotAggregationColumns: [ { ColumnId: 'gold', AggFunc: 'sum', }, { ColumnId: 'silver', AggFunc: 'sum', }, { ColumnId: 'bronze', AggFunc: 'sum', }, ], }, { Name: 'Group Total After', PivotColumns: ['sport', 'year'], PivotGroupedColumns: ['country'], PivotColumnTotal: 'after', PivotAggregationColumns: [ { ColumnId: 'gold', AggFunc: 'sum', }, { ColumnId: 'silver', AggFunc: 'sum', }, { ColumnId: 'bronze', AggFunc: 'sum', }, ], }, ], }, }, }; ``` ```ts import {ColDef} from 'ag-grid-enterprise'; export const columnDefs: ColDef[] = [ { field: 'id', cellDataType: 'number', hide: true, lockVisible: true, suppressFiltersToolPanel: true, suppressColumnsToolPanel: true, }, {field: 'country', cellDataType: 'text', enableRowGroup: true}, {field: 'athlete', cellDataType: 'text', enableRowGroup: true}, {field: 'sport', cellDataType: 'text', enablePivot: true}, {field: 'year', cellDataType: 'number', enablePivot: true}, {field: 'gold', cellDataType: 'number', enableValue: true}, {field: 'silver', cellDataType: 'number', enableValue: true}, {field: 'bronze', cellDataType: 'number', enableValue: true}, {field: 'age', cellDataType: 'number'}, {field: 'date', cellDataType: 'date'}, {field: 'total', cellDataType: 'number'}, ]; ``` ```ts import {ColDef, GridOptions, themeBalham} from 'ag-grid-enterprise'; import {IOlympicData} from './rowData'; import {columnDefs} from './columnDefs'; export const gridOptions: GridOptions = { theme: themeBalham, defaultColDef: { resizable: true, sortable: true, editable: 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 export interface IOlympicData { athlete: string; age: number; country: string; year: number; date: string; sport: string; gold: number; silver: number; bronze: number; total: number; } export const getRowData = (limit?: number) => { const rawData = limit ? rowData.slice(0, limit) : rowData; return rawData.map((item, index) => ({...item, id: index})); }; export const rowData: IOlympicData[] = [ { athlete: 'Michael Phelps', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 8, silver: 0, bronze: 0, total: 8, }, { athlete: 'Michael Phelps', age: 19, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 6, silver: 0, bronze: 2, total: 8, }, { athlete: 'Michael Phelps', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 4, silver: 2, bronze: 0, total: 6, }, { athlete: 'Natalie Coughlin', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 2, bronze: 3, total: 6, }, { athlete: 'Aleksey Nemov', age: 24, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 2, silver: 1, bronze: 3, total: 6, }, { athlete: 'Alicia Coutts', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 3, bronze: 1, total: 5, }, { athlete: 'Missy Franklin', age: 17, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 4, silver: 0, bronze: 1, total: 5, }, { athlete: 'Ryan Lochte', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 2, bronze: 1, total: 5, }, { athlete: 'Allison Schmitt', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 3, silver: 1, bronze: 1, total: 5, }, { athlete: 'Natalie Coughlin', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 2, silver: 2, bronze: 1, total: 5, }, { athlete: 'Ian Thorpe', age: 17, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 3, silver: 2, bronze: 0, total: 5, }, { athlete: 'Dara Torres', age: 33, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 3, total: 5, }, { athlete: 'Cindy Klassen', age: 26, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 2, bronze: 2, total: 5, }, { athlete: 'Nastia Liukin', age: 18, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 3, bronze: 1, total: 5, }, { athlete: 'Marit Bjørgen', age: 29, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 3, silver: 1, bronze: 1, total: 5, }, { athlete: 'Sun Yang', age: 20, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 1, total: 4, }, { athlete: 'Kirsty Coventry', age: 24, country: 'Zimbabwe', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 3, bronze: 0, total: 4, }, { athlete: 'Libby Lenton-Trickett', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 1, bronze: 1, total: 4, }, { athlete: 'Ryan Lochte', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 2, total: 4, }, { athlete: 'Inge de Bruijn', age: 30, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 2, total: 4, }, { athlete: 'Petria Thomas', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 3, silver: 1, bronze: 0, total: 4, }, { athlete: 'Ian Thorpe', age: 21, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 2, silver: 1, bronze: 1, total: 4, }, { athlete: 'Inge de Bruijn', age: 27, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 3, silver: 1, bronze: 0, total: 4, }, { athlete: 'Gary Hall Jr.', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 1, bronze: 1, total: 4, }, { athlete: 'Michael Klim', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 2, bronze: 0, total: 4, }, { athlete: "Susie O'Neill", age: 27, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 3, bronze: 0, total: 4, }, { athlete: 'Jenny Thompson', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 3, silver: 0, bronze: 1, total: 4, }, { athlete: 'Pieter van den Hoogenband', age: 22, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 2, total: 4, }, { athlete: 'An Hyeon-Su', age: 20, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 3, silver: 0, bronze: 1, total: 4, }, { athlete: 'Aliya Mustafina', age: 17, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 2, total: 4, }, { athlete: 'Shawn Johnson', age: 16, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 3, bronze: 0, total: 4, }, { athlete: 'Dmitry Sautin', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 1, bronze: 2, total: 4, }, { athlete: 'Leontien Zijlaard-van Moorsel', age: 30, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 3, silver: 1, bronze: 0, total: 4, }, { athlete: 'Petter Northug Jr.', age: 24, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 2, silver: 1, bronze: 1, total: 4, }, { athlete: 'Ole Einar Bjørndalen', age: 28, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 4, silver: 0, bronze: 0, total: 4, }, { athlete: 'Janica Kostelic', age: 20, country: 'Croatia', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 3, silver: 1, bronze: 0, total: 4, }, { athlete: 'Nathan Adrian', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Yannick Agnel', age: 20, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Brittany Elmslie', age: 18, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Matt Grevers', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Ryosuke Irie', age: 22, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Cullen Jones', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Ranomi Kromowidjojo', age: 21, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Camille Muffat', age: 22, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Mel Schlanger', age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Emily Seebohm', age: 20, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Rebecca Soni', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Satomi Suzuki', age: 21, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Dana Vollmer', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Alain Bernard', age: 25, country: 'France', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'László Cseh Jr.', age: 22, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 3, bronze: 0, total: 3, }, { athlete: 'Matt Grevers', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Margaret Hoelzer', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Katie Hoff', age: 19, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Leisel Jones', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Kosuke Kitajima', age: 25, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Andrew Lauterstein', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Jason Lezak', age: 32, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Pang Jiaying', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Aaron Peirsol', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Steph Rice', age: 20, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Jess Schipper', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Rebecca Soni', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Eamon Sullivan', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Dara Torres', age: 41, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 3, bronze: 0, total: 3, }, { athlete: 'Amanda Beard', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Antje Buschschulte', age: 25, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 3, total: 3, }, { athlete: 'Kirsty Coventry', age: 20, country: 'Zimbabwe', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Ian Crocker', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Grant Hackett', age: 24, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Brendan Hansen', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Jodie Henry', age: 20, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Otylia Jedrzejczak', age: 20, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Leisel Jones', age: 18, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Kosuke Kitajima', age: 21, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Laure Manaudou', age: 17, country: 'France', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Aaron Peirsol', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Kaitlin Sandeno', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Roland Schoeman', age: 24, country: 'South Africa', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Pieter van den Hoogenband', age: 26, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Therese Alshammar', age: 23, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Yana Klochkova', age: 18, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Lenny Krayzelburg', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Massimiliano Rosolino', age: 22, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Petria Thomas', age: 25, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Matt Welsh', age: 23, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Lee Jeong-Su', age: 20, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Apolo Anton Ohno', age: 27, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Wang Meng', age: 24, country: 'China', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Jin Seon-Yu', age: 17, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Lee Ho-Seok', age: 19, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Apolo Anton Ohno', age: 23, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Wang Meng', age: 20, country: 'China', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Marc Gagnon', age: 26, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Yang Yang (A)', age: 25, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Stephanie Beckert', age: 21, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Martina Sáblíková', age: 22, country: 'Czech Republic', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Enrico Fabris', age: 24, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Chad Hedrick', age: 28, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Jochem Uytdehaage', age: 25, country: 'Netherlands', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Sabine Völker', age: 28, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Gregor Schlierenzauer', age: 20, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Lars Bystøl', age: 27, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Johnny Spillane', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 0, silver: 3, bronze: 0, total: 3, }, { athlete: 'Felix Gottwald', age: 30, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Georg Hettich', age: 27, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Felix Gottwald', age: 26, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 0, silver: 0, bronze: 3, total: 3, }, { athlete: 'Samppa Lajunen', age: 22, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Aly Raisman', age: 18, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Kohei Uchimura', age: 23, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Zou Kai', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Cheng Fei', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Yang Wei', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Yang Yilin', age: 15, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Zou Kai', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Marian Dragulescu', age: 23, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 2, total: 3, }, { athlete: 'Paul Hamm', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Carly Patterson', age: 16, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Catalina Ponor', age: 16, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Simona Amânar', age: 20, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Svetlana Khorkina', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Yekaterina Lobaznyuk', age: 17, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Yelena Zamolodchikova', age: 17, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Guo Shuang', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Chris Hoy', age: 32, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Bradley Wiggins', age: 24, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Florian Rousseau', age: 26, country: 'France', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Justyna Kowalczyk', age: 27, country: 'Poland', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Johan Olsson', age: 29, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Stefania Belmondo', age: 33, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Yuliya Chepalova', age: 25, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Frode Estil', age: 29, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Bente Skari-Martinsen', age: 29, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Magdalena Neuner', age: 23, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Emil Hegle Svendsen', age: 24, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Albina Akhatova', age: 29, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Ole Einar Bjørndalen', age: 32, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 2, bronze: 1, total: 3, }, { athlete: 'Sven Fischer', age: 34, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Martina Glagow-Beck', age: 26, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 3, bronze: 0, total: 3, }, { athlete: 'Michael Greis', age: 29, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Kati Wilhelm', age: 29, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Kati Wilhelm', age: 25, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 2, silver: 1, bronze: 0, total: 3, }, { athlete: 'Yohan Blake', age: 22, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Usain Bolt', age: 25, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Allyson Felix', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Shelly-Ann Fraser-Pryce', age: 25, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 2, bronze: 0, total: 3, }, { athlete: 'Carmelita Jeter', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Usain Bolt', age: 21, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 3, silver: 0, bronze: 0, total: 3, }, { athlete: 'Veronica Campbell-Brown', age: 22, country: 'Jamaica', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 2, silver: 0, bronze: 1, total: 3, }, { athlete: 'Justin Gatlin', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Bode Miller', age: 32, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Aksel Lund Svindal', age: 27, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Anja Pärson', age: 24, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 2, total: 3, }, { athlete: 'Stephan Eberharter', age: 32, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 1, silver: 1, bronze: 1, total: 3, }, { athlete: 'Ding Ning', age: 22, country: 'China', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Feng Tian Wei', age: 25, country: 'Singapore', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Li Xiaoxia', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Dmitrij Ovtcharov', age: 23, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Wang Hao', age: 28, country: 'China', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Zhang Jike', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Guo Yue', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Ma Lin', age: 28, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Wang Hao', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Wang Liqin', age: 30, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Wang Nan', age: 29, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Zhang Yining', age: 26, country: 'China', year: 2008, date: '24/08/2008', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Zhang Yining', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Kong Linghui', age: 24, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Li Ju', age: 24, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Liu Guoliang', age: 24, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Wang Nan', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Table Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Viktoriya Azarenko', age: 22, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Mike Bryan', age: 34, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Andy Murray', age: 25, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Serena Williams', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Fernando González', age: 24, country: 'Chile', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Nicolás Massú', age: 26, country: 'Chile', year: 2004, date: '29/08/2004', sport: 'Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Venus Williams', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Tennis', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ona Carbonell', age: 22, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Andrea Fuentes', age: 29, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Huang Xuechen', age: 22, country: 'China', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Nataliya Ishchenko', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Liu Ou', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Svetlana Romashina', age: 22, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Anastasiya Davydova', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Andrea Fuentes', age: 25, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Gemma Mengual', age: 31, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Anastasiya Yermakova', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Alison Bartosik', age: 21, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Anastasiya Davydova', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Anna Kozlova', age: 31, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Miya Tachibana', age: 29, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Miho Takeda', age: 27, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Anastasiya Yermakova', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Olga Brusnikina', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Mariya Kiselyova', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Miya Tachibana', age: 25, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Miho Takeda', age: 24, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Synchronized Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Becky Adlington', age: 23, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Bronte Barratt', age: 23, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Elizabeth Beisel', age: 19, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Mireia Belmonte', age: 21, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Ricky Berens', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Aleksandra Gerasimenya', age: 26, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Brendan Hansen', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Jessica Hardy', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Chad le Clos', age: 20, country: 'South Africa', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Clément Lefert', age: 24, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Amaury Leveaux', age: 26, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'James Magnussen', age: 21, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Takeshi Matsuda', age: 28, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Oussama Mellouli', age: 28, country: 'Tunisia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Park Tae-Hwan', age: 22, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Christian Sprenger', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Jeremy Stravius', age: 24, country: 'France', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Aya Terakawa', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Nick Thoman', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Marleen Veldhuis', age: 33, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Ye Shiwen', age: 16, country: 'China', year: 2012, date: '12/08/2012', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Becky Adlington', age: 19, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Leith Brodie', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Cate Campbell', age: 16, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'César Cielo Filho', age: 21, country: 'Brazil', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Hugues Duboscq', age: 26, country: 'France', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Felicity Galvez', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Grant Hackett', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Kara Lynn Joyce', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Amaury Leveaux', age: 22, country: 'France', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Christine Magnuson', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Patrick Murphy', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Park Tae-Hwan', age: 18, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Shayne Reese', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Brenton Rickard', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Mel Schlanger', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Julia Smit', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Britta Steffen', age: 24, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Hayden Stoeckel', age: 24, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Matt Targett', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Peter Vanderkaay', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Arkady Vyachanin', age: 24, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Garrett Weber-Gale', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Lindsay Benko', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Gary Hall Jr.', age: 29, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Brooke Hanson', age: 26, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kara Lynn Joyce', age: 18, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Klete Keller', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Yana Klochkova', age: 22, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Rachel Komisarz', age: 27, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Libby Lenton-Trickett', age: 19, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Jason Lezak', age: 28, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Ryan Lochte', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Alice Mills', age: 18, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Tomomi Morita', age: 19, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Markus Rogan', age: 22, country: 'Austria', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Jenny Thompson', age: 31, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Franziska van Almsick', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Neil Walker', age: 28, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Amanda Weir', age: 18, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Takashi Yamamoto', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Brooke Bennett', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Beatrice Coada-Caslaru', age: 25, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Josh Davis', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Tom Dolan', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Anthony Ervin', age: 19, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Domenico Fioravanti', age: 23, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Grant Hackett', age: 20, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Geoff Huegill', age: 21, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Leisel Jones', age: 15, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Klete Keller', age: 18, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Jason Lezak', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Diana Mocanu', age: 16, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Martina Moravcová', age: 24, country: 'Slovakia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Ed Moses', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Diana Munz', age: 18, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Mai Nakamura', age: 21, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Todd Pearson', age: 22, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Adam Pine', age: 24, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Claudia Poll', age: 27, country: 'Costa Rica', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Megan Quann-Jendrick', age: 16, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Giaan Rooney', age: 17, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Courtney Shealy', age: 22, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ashley Tappin', age: 25, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Stev Theloke', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Amy Van Dyken', age: 27, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Neil Walker', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Swimming', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'J. R. Celski', age: 19, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Charles Hamelin', age: 25, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Lee Ho-Seok', age: 23, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Park Seung-Hui', age: 17, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Katherine Reutter', age: 21, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Seong Si-Baek', age: 22, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Marianne St-Gelais', age: 19, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'François-Louis Tremblay', age: 29, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Zhou Yang', age: 18, country: 'China', year: 2010, date: '28/02/2010', sport: 'Short-Track Speed Skating', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Choi Eun-Gyeong', age: 21, country: 'South Korea', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Anouk Leblanc-Boucher', age: 21, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'François-Louis Tremblay', age: 25, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Short-Track Speed Skating', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Choi Eun-Gyeong', age: 17, country: 'South Korea', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Go Gi-Hyeon', age: 15, country: 'South Korea', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Jonathan Guilmette', age: 23, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Li Jiajun', age: 26, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Apolo Anton Ohno', age: 19, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Evgeniya Radanova', age: 24, country: 'Bulgaria', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Mathieu Turcotte', age: 25, country: 'Canada', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Wang Chunlu', age: 23, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Yang Yang (S)', age: 24, country: 'China', year: 2002, date: '24/02/2002', sport: 'Short-Track Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Shani Davis', age: 27, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kristina Groves', age: 33, country: 'Canada', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Chad Hedrick', age: 32, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Sven Kramer', age: 23, country: 'Netherlands', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Lee Seung-Hun', age: 21, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Mo Tae-Beom', age: 21, country: 'South Korea', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Ivan Skobrev', age: 27, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Mark Tuitert', age: 29, country: 'Netherlands', year: 2010, date: '28/02/2010', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Joey Cheek', age: 26, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Shani Davis', age: 23, country: 'United States', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Anni Friesinger-Postma', age: 29, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Kristina Groves', age: 29, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Clara Hughes', age: 33, country: 'Canada', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Sven Kramer', age: 19, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Claudia Pechstein', age: 33, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Carl Verheijen', age: 30, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Erben Wennemars', age: 30, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Ireen Wüst', age: 19, country: 'Netherlands', year: 2006, date: '26/02/2006', sport: 'Speed Skating', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Derek Parra', age: 31, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Claudia Pechstein', age: 29, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Jennifer Rodriguez', age: 25, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Speed Skating', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Simon Ammann', age: 28, country: 'Switzerland', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Adam Malysz', age: 32, country: 'Poland', year: 2010, date: '28/02/2010', sport: 'Ski Jumping', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Matti Hautamäki', age: 24, country: 'Finland', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Andreas Kofler', age: 21, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Roar Ljøkelsøy', age: 29, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Thomas Morgenstern', age: 19, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Ski Jumping', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Simon Ammann', age: 20, country: 'Switzerland', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Sven Hannawald', age: 27, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Matti Hautamäki', age: 20, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Adam Malysz', age: 24, country: 'Poland', year: 2002, date: '24/02/2002', sport: 'Ski Jumping', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Niccolò Campriani', age: 24, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Jin Jong-O', age: 32, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Olena Kostevych', age: 27, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Shooting', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Jin Jong-O', age: 28, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Katerina Kurková-Emmons', age: 24, country: 'Czech Republic', year: 2008, date: '24/08/2008', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Lyubov Galkina', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Mariya Grozdeva', age: 32, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Lee Bo-Na', age: 23, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Mikhail Nestruyev', age: 35, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Igor Basinsky', age: 37, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Tao Luna', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Shooting', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kim Crow', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Rowing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Georgeta Damian-Andrunache', age: 32, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Viorica Susanu', age: 32, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Rowing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Georgeta Damian-Andrunache', age: 28, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Viorica Susanu', age: 28, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Rowing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Georgeta Damian-Andrunache', age: 24, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Doina Ignat', age: 31, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Pieta van Dishoeck', age: 28, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Eeke van Nes', age: 31, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Rowing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Bill Demong', age: 29, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Bernhard Gruber', age: 27, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Nordic Combined', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Magnus Moan', age: 22, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Nordic Combined', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Ronny Ackermann', age: 24, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Jaakko Tallus', age: 20, country: 'Finland', year: 2002, date: '24/02/2002', sport: 'Nordic Combined', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Denis Ablyazin', age: 19, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Chen Yibing', age: 27, country: 'China', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Gabby Douglas', age: 16, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Feng Zhe', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Sandra Izbasa', age: 22, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Viktoriya Komova', age: 17, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'McKayla Maroney', age: 16, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Marcel Nguyen', age: 24, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Mariya Paseka', age: 17, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Catalina Ponor', age: 24, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Louis Smith', age: 23, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Max Whitlock', age: 19, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Chen Yibing', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Anton Golotsutskov', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'He Kexin', age: 16, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Jonathan Horton', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Sandra Izbasa', age: 18, country: 'Romania', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Li Xiaopeng', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Kohei Uchimura', age: 19, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Xiao Qin', age: 23, country: 'China', year: 2008, date: '24/08/2008', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Alexandra Eremia', age: 17, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Annia Hatch', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Terin Humphrey', age: 18, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Takehiro Kashima', age: 24, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Svetlana Khorkina', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Courtney Kupets', age: 18, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Anna Pavlova', age: 16, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Monica Rosu', age: 17, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Dana Sofronie', age: 16, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Hiroyuki Tomita', age: 23, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Marius Urzica', age: 28, country: 'Romania', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Isao Yoneda', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Yordan Yovchev', age: 31, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Oleksandr Beresh', age: 22, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Aleksey Bondarenko', age: 22, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Lee Ju-Hyeong', age: 27, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Li Xiaopeng', age: 19, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Liu Xuan', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Maria Olaru', age: 18, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yelena Produnova', age: 20, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Andreea Raducan', age: 16, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yang Wei', age: 20, country: 'China', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yordan Yovchev', age: 27, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Gymnastics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Elisa Di Francisca', age: 29, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Arianna Errigo', age: 24, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Diego Occhiuzzi', age: 31, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Sun Yujie', age: 19, country: 'China', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Valentina Vezzali', age: 38, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Stefano Carozzo', age: 29, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Margherita Granbassi', age: 28, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Sada Jacobson', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Fabrice Jeannet', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Nicolas Lopez', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Matteo Tagliariol', age: 25, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Valentina Vezzali', age: 34, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Becca Ward', age: 18, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Mariel Zagunis', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Andrea Cassarà', age: 20, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Laura Flessel-Colovic', age: 32, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Aldo Montano', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Maureen Nisima', age: 23, country: 'France', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Salvatore Sanzo', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Fencing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Mathieu Gourdain', age: 26, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Gianna Hablützel-Bürki', age: 30, country: 'Switzerland', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Rita König', age: 23, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Wiradech Kothny', age: 21, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Hugues Obry', age: 27, country: 'France', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Giovanna Trillini', age: 30, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Valentina Vezzali', age: 26, country: 'Italy', year: 2000, date: '01/10/2000', sport: 'Fencing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Sandra Auffarth', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Laura Bechtolsheimer', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Adelinde Cornelissen', age: 33, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Charlotte Dujardin', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Michael Jung', age: 29, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Gerco Schröder', age: 34, country: 'Netherlands', year: 2012, date: '12/08/2012', sport: 'Equestrian', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Tina Cook', age: 37, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Heike Kemmer', age: 46, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Eric Lamaze', age: 40, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Beezie Madden', age: 44, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Hinrich Romeike', age: 45, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Anky van Grunsven', age: 40, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Isabell Werth', age: 39, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Beatriz Ferrer-Salat', age: 38, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Pippa Funnell', age: 35, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Chris Kappler', age: 37, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Marco Kutscher', age: 29, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Leslie Law', age: 39, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Ulla Salzgeber', age: 46, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kim Severson', age: 30, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Equestrian', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Andrew Hoy', age: 41, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: "David O'Connor", age: 38, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Ulla Salzgeber', age: 42, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Anky van Grunsven', age: 32, country: 'Netherlands', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Isabell Werth', age: 31, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Equestrian', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'David Boudia', age: 23, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Chen Ruolin', age: 19, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'He Zi', age: 21, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Qin Kai', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Wu Minxia', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ilya Zakharov', age: 21, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Chen Ruolin', age: 15, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Gleb Galperin', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Guo Jingjing', age: 26, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Yuliya Pakhalina', age: 30, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Qin Kai', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Wang Xin', age: 16, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Wu Minxia', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Guo Jingjing', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Mathew Helm', age: 23, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Lao Lishi', age: 16, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Chantelle Michell-Newbery', age: 27, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Robert Newbery', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Yuliya Pakhalina', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Tian Liang', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Wu Minxia', age: 18, country: 'China', year: 2004, date: '29/08/2004', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Fu Mingxia', age: 22, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Guo Jingjing', age: 18, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Hu Jia', age: 17, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Li Na', age: 16, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Anne Montminy', age: 25, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Tian Liang', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Xiong Ni', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Diving', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Grégory Baugé', age: 27, country: 'France', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Ed Clancy', age: 27, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Sarah Hammer', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Chris Hoy', age: 36, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Jason Kenny', age: 24, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Maximilian Levy', age: 25, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Anna Meares', age: 28, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Vicki Pendleton', age: 31, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Laura Trott', age: 20, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Olga Zabelinskaya', age: 32, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Cycling', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Mickaël Bourgain', age: 28, country: 'France', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Fabian Cancellara', age: 27, country: 'Switzerland', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Jason Kenny', age: 20, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Joan Llaneras', age: 39, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Hayden Roulston', age: 27, country: 'New Zealand', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Bradley Wiggins', age: 28, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ryan Bayley', age: 22, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Graeme Brown', age: 25, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Sergi Escobar', age: 29, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Rob Hayles', age: 31, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Brad McGee', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Anna Meares', age: 20, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Stefan Nimke', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Olga Slyusareva', age: 35, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Arnaud Tournant', age: 26, country: 'France', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'René Wolff', age: 26, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Leontien Zijlaard-van Moorsel', age: 34, country: 'Netherlands', year: 2004, date: '29/08/2004', sport: 'Cycling', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Félicia Ballanger', age: 29, country: 'France', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Robert Bartko', age: 24, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Jens Fiedler', age: 30, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Jens Lehmann', age: 32, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Gary Neiwand', age: 34, country: 'Australia', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Jason Queally', age: 30, country: 'Great Britain', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Jan Ullrich', age: 26, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Cycling', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Lukáš Bauer', age: 32, country: 'Czech Republic', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Anna Haag', age: 23, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Marcus Hellner', age: 24, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Charlotte Kalla', age: 22, country: 'Sweden', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Claudia Künzel-Nystad', age: 32, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Aino-Kaisa Saarinen', age: 31, country: 'Finland', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Evi Sachenbacher-Stehle', age: 29, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Axel Teichmann', age: 30, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Cross Country Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Tobias Angerer', age: 28, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Yuliya Chepalova', age: 29, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yevgeny Dementyev', age: 23, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Giorgio Di Centa', age: 33, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Thobias Fredriksson', age: 30, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Claudia Künzel-Nystad', age: 28, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Björn Lind', age: 27, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Yevgeniya Medvedeva', age: 29, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Katerina Neumannová', age: 32, country: 'Czech Republic', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Pietro Piller Cottrer', age: 31, country: 'Italy', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Kristina Šmigun-Vähi', age: 28, country: 'Estonia', year: 2006, date: '26/02/2006', sport: 'Cross Country Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Thomas Alsgaard', age: 30, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Viola Bauer', age: 25, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Anita Moen-Guidon', age: 34, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Katerina Neumannová', age: 28, country: 'Czech Republic', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Evi Sachenbacher-Stehle', age: 21, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kristen Skjeldal', age: 34, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Andrus Veerpalu', age: 31, country: 'Estonia', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Cristian Zorzi', age: 29, country: 'Italy', year: 2002, date: '24/02/2002', sport: 'Cross Country Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Tina Dietze', age: 24, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Natasa Douchev-Janics', age: 30, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Katalin Kovács', age: 36, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Danuta Kozák', age: 25, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Inna Osypenko-Radomska', age: 29, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Franziska Weber', age: 23, country: 'Germany', year: 2012, date: '12/08/2012', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Tim Brabants', age: 31, country: 'Great Britain', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'David Cal', age: 25, country: 'Spain', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Natasa Douchev-Janics', age: 26, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Christian Gille', age: 32, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Katalin Kovács', age: 32, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Vadim Makhnyov', age: 28, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Roman Petrushenko', age: 27, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Katrin Wagner-Augustin', age: 30, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Ken Wallace', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Tomasz Wylenzek', age: 25, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Canoeing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Nathan Baggaley', age: 28, country: 'Australia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'David Cal', age: 21, country: 'Spain', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Andreas Dittmer', age: 32, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Natasa Douchev-Janics', age: 22, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Birgit Fischer-Schmidt', age: 42, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Aleksandr Kostoglod', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Katalin Kovács', age: 28, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Aleksandr Kovalyov', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Eirik Verås Larsen', age: 28, country: 'Norway', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Carolin Leonhardt', age: 19, country: 'Germany', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Adam Van Koeverden', age: 22, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Andreas Dittmer', age: 28, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Birgit Fischer-Schmidt', age: 38, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Knut Holmann', age: 32, country: 'Norway', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Zoltán Kammerer', age: 22, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Katalin Kovács', age: 24, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Petar Merkov', age: 23, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Florin Popescu', age: 26, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Mitica Pricop', age: 22, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Botond Storcz', age: 25, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Szilvia Szabó', age: 21, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Katrin Wagner-Augustin', age: 22, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Canoeing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Kevin Kuske', age: 31, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'André Lange', age: 36, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Bobsleigh', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Martin Annen', age: 32, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Beat Hefti', age: 28, country: 'Switzerland', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Kevin Kuske', age: 27, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'André Lange', age: 32, country: 'Germany', year: 2006, date: '26/02/2006', sport: 'Bobsleigh', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ole Einar Bjørndalen', age: 36, country: 'Norway', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Marie Laure Brunet', age: 21, country: 'France', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Marie Dorin', age: 23, country: 'France', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Simone Hauswald', age: 30, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Vincent Jay', age: 24, country: 'France', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Anastasia Kuzmina', age: 25, country: 'Slovakia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Christoph Sumann', age: 34, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Yevgeny Ustyugov', age: 24, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Olga Zaytseva', age: 31, country: 'Russia', year: 2010, date: '28/02/2010', sport: 'Biathlon', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Florence Baverel-Robert', age: 31, country: 'France', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Vincent Defrasne', age: 28, country: 'France', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Halvard Hanevold', age: 36, country: 'Norway', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Svetlana Ishmuratova', age: 33, country: 'Russia', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Anna-Carin Olofsson-Zidek', age: 32, country: 'Sweden', year: 2006, date: '26/02/2006', sport: 'Biathlon', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Uschi Disl', age: 31, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Sven Fischer', age: 30, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Ricco Groß', age: 31, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Andrea Henkel', age: 24, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Frank Luck', age: 34, country: 'Germany', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Raphaël Poirée', age: 27, country: 'France', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Olga Pylyova-Medvedtseva', age: 26, country: 'Russia', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Liv Grete Skjelbreid-Poirée', age: 27, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Magdalena Wallin-Forsberg', age: 34, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Biathlon', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Zhao Yunlei', age: 25, country: 'China', year: 2012, date: '12/08/2012', sport: 'Badminton', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Lee Hyo-Jeong', age: 27, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yu Yang', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Badminton', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Gao Ling', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Badminton', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Gao Ling', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Badminton', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Nataliya Antyukh', age: 31, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Veronica Campbell-Brown', age: 30, country: 'Jamaica', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Vivian Cheruiyot', age: 28, country: 'Kenya', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Will Claye', age: 21, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Tirunesh Dibaba', age: 27, country: 'Ethiopia', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Mo Farah', age: 29, country: 'Great Britain', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Justin Gatlin', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Lalonde Gordon', age: 23, country: 'Trinidad and Tobago', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Sanya Richards-Ross', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'DeeDee Trotter', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Elvan Abeylegesse', age: 25, country: 'Turkey', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Kenenisa Bekele', age: 26, country: 'Ethiopia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Kerron Clement', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Tirunesh Dibaba', age: 23, country: 'Ethiopia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Walter Dix', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Allyson Felix', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yuliya Gushchina', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Tatyana Lebedeva', age: 32, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'LaShawn Merritt', age: 22, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'David Neville', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Sanya Richards-Ross', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Kerron Stewart', age: 24, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Jared Tallent', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Angelo Taylor', age: 29, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Richard Thompson', age: 23, country: 'Trinidad and Tobago', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Jeremy Wariner', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Shericka Williams', age: 22, country: 'Jamaica', year: 2008, date: '24/08/2008', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Nataliya Antyukh', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Kenenisa Bekele', age: 22, country: 'Ethiopia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Derrick Brew', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Shawn Crawford', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Hicham El Guerrouj', age: 29, country: 'Morocco', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Maurice Greene', age: 30, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Otis Harris', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kelly Holmes', age: 34, country: 'Great Britain', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Tatyana Lebedeva', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Jeremy Wariner', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Ato Boldon', age: 26, country: 'Trinidad and Tobago', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Pauline Davis-Thompson', age: 34, country: 'Bahamas', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Lorraine Graham', age: 27, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Maurice Greene', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Greg Haughton', age: 26, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Deon Hemmings', age: 31, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Robert Korzeniowski', age: 32, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Tayna Lawrence', age: 25, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Beverly McDonald', age: 30, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Merlene Ottey-Page', age: 40, country: 'Jamaica', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Irina Privalova', age: 31, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Gabriela Szabo', age: 24, country: 'Romania', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Gete Wami', age: 25, country: 'Ethiopia', year: 2000, date: '01/10/2000', sport: 'Athletics', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Elisabeth Görgl', age: 28, country: 'Austria', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Lindsey Kildow-Vonn', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Ivica Kostelic', age: 30, country: 'Croatia', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Julia Mancuso', age: 25, country: 'United States', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Tina Maze', age: 26, country: 'Slovenia', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Maria Riesch', age: 25, country: 'Germany', year: 2010, date: '28/02/2010', sport: 'Alpine Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Michaela Dorfmeister', age: 32, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Janica Kostelic', age: 24, country: 'Croatia', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Hermann Maier', age: 33, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Benjamin Raich', age: 27, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Marlies Schild', age: 24, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Rainer Schönfelder', age: 28, country: 'Austria', year: 2006, date: '26/02/2006', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Kjetil André Aamodt', age: 30, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Renate Götschl', age: 26, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Lasse Kjus', age: 31, country: 'Norway', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Bode Miller', age: 24, country: 'United States', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 2, bronze: 0, total: 2, }, { athlete: 'Anja Pärson', age: 20, country: 'Sweden', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Benjamin Raich', age: 23, country: 'Austria', year: 2002, date: '24/02/2002', sport: 'Alpine Skiing', gold: 0, silver: 0, bronze: 2, total: 2, }, { athlete: 'Ki Bo-Bae', age: 24, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Oh Jin-Hyek', age: 30, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Archery', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Park Gyeong-Mo', age: 32, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Park Seong-Hyeon', age: 25, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Yun Ok-Hui', age: 23, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Zhang Juanjuan', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Archery', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Lee Seong-Jin', age: 19, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Park Seong-Hyeon', age: 21, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Archery', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Kim Nam-Sun', age: 20, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 1, silver: 1, bronze: 0, total: 2, }, { athlete: 'Kim Su-Nyeong', age: 29, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 1, silver: 0, bronze: 1, total: 2, }, { athlete: 'Vic Wunderle', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 0, silver: 1, bronze: 1, total: 2, }, { athlete: 'Yun Mi-Jin', age: 17, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Archery', gold: 2, silver: 0, bronze: 0, total: 2, }, { athlete: 'Artur Aleksanyan', age: 20, country: 'Armenia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Valeriy Andriitsev', age: 25, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rövs?n Bayramov', age: 25, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jordan Burroughs', age: 24, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Clarissa Chun', age: 30, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yogeshwar Dutt', age: 29, country: 'India', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jaime Espinal', age: 27, country: 'Puerto Rico', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Johan Eurén', age: 27, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karam Gaber', age: 32, country: 'Egypt', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Daniyal Gadzhiyev', age: 26, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Komeil Ghasemi', age: 24, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giorgi Gogshelidze', age: 32, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sadegh Goudarzi', age: 24, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Steeve Guénot', age: 26, country: 'France', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carol Huynh', age: 31, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kaori Icho', age: 28, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Damian Janikowski', age: 23, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jing Ruixue', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Arsen Julfalakyan', age: 25, country: 'Armenia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Riza Kayaalp', age: 22, country: 'Turkey', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandras Kazakevicius', age: 26, country: 'Lithuania', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vladimer Khinchegashvili', age: 21, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alan Khugayev', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kim Hyeon-Wu', age: 23, country: 'South Korea', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Besik Kudukhov', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sushil Kumar', age: 29, country: 'India', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zaur Kuramagomedov', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ehsan Naser Lashgari', age: 26, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Revaz Lashkhi', age: 24, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jimmy Lidberg', age: 30, country: 'Sweden', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Liván López', age: 30, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mijaín López', age: 29, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamás Lorincz', age: 25, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bilyal Makhov', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gyuzel Manyurova', age: 34, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dato Marsagishvili', age: 21, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ryutaro Matsumoto', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Péter Módos', age: 24, country: 'Hungary', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Davit Modzmanashvili', age: 25, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heiki Nabi', age: 27, country: 'Estonia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Omid Noroozi', age: 26, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Hitomi Obara', age: 31, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dzhamal Otarsultanov', age: 25, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Xetaq Qazyumov', age: 29, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yuliya Ratkeviç', age: 27, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jackeline Rentería', age: 26, country: 'Colombia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ghasem Rezaei', age: 26, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Coleman Scott', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mingiyan Semyonov', age: 22, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Soronzonboldyn Battsetseg', age: 22, country: 'Mongolia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hamid Soryan', age: 26, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mariya Stadnik', age: 24, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'S?rif S?rifov', age: 23, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Akzhurek Tanatarov', age: 25, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Artur Taymazov', age: 33, country: 'Uzbekistan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Soslan Tigiyev', age: 28, country: 'Uzbekistan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rustam Totrov', age: 28, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Denis Tsargush', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Manuchar Tskhadaia', age: 27, country: 'Georgia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maider Unda', age: 35, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jake Varner', age: 26, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tonya Verbeek', age: 34, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roman Vlasov', age: 21, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lyubov Volosova', age: 29, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Vorobyova', age: 21, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yang Kyong-Il', age: 23, country: 'North Korea', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatsuhiro Yonemitsu', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Saori Yoshida', age: 29, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Shinichi Yumoto', age: 27, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stanka Zlateva', age: 29, country: 'Bulgaria', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Emin ?hm?dov', age: 25, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Togrul ?sg?rov', age: 19, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yusuf Abdusalomov', age: 30, country: 'Tajikistan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bakhtiyar Akhmedov', age: 21, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Islam-Beka Albiyev', age: 19, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roman Amoyan', age: 24, country: 'Armenia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nazmi Avluca', age: 31, country: 'Turkey', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Khasan Baroyev', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mavlet Batyrov', age: 24, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rövs?n Bayramov', age: 21, country: 'Azerbaijan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kanat Begaliyev', age: 24, country: 'Kyrgyzstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Henry Cejudo', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chang Yongxiang', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Taras Danko', age: 28, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mirko Englich', age: 29, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vasyl Fedoryshyn', age: 27, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zoltán Fodor', age: 23, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Murad Gaydarov', age: 28, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giorgi Gogshelidze', age: 28, country: 'Georgia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Christophe Guénot', age: 29, country: 'France', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Steeve Guénot', age: 22, country: 'France', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kyoko Hamaguchi', age: 30, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Carol Huynh', age: 27, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chiharu Icho', age: 26, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kaori Icho', age: 24, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Manuchar K'virk'elia", age: 29, country: 'Georgia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alyona Kartashova', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Georgy Ketoyev', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aslanbek Khushtov', age: 28, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Besik Kudukhov', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sushil Kumar', age: 25, country: 'India', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mijaín López', age: 25, country: 'Cuba', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aset Mambetov', age: 26, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nazyr Mankiyev', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tomohiro Matsunaga', age: 28, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iryna Merleni-Mykulchyn', age: 26, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Randi Miller', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Revaz Mindorashvili', age: 32, country: 'Georgia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrea Minguzzi', age: 26, country: 'Italy', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mindaugas Mizgaitis', age: 28, country: 'Lithuania', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Seyed Mohammadi', age: 28, country: 'Iran', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sharvani Muradov', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Musulbes', age: 36, country: 'Slovakia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marid Mutalimov', age: 28, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Park Eun-Chul', age: 27, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yury Patrikeyev', age: 28, country: 'Armenia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xetaq Qazyumov', age: 25, country: 'Azerbaijan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jackeline Rentería', age: 22, country: 'Colombia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Vitaliy R?himov', age: 23, country: 'Azerbaijan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ramazan Sahin', age: 25, country: 'Turkey', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Buvaisa Saytiyev', age: 33, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mikhail Semyonov', age: 24, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yelena Shalygina', age: 21, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andriy Stadnik', age: 26, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mariya Stadnik', age: 20, country: 'Azerbaijan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Artur Taymazov', age: 29, country: 'Uzbekistan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nurbakyt Tengizbayev', age: 25, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kiril Terziev', age: 24, country: 'Bulgaria', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Soslan Tigiyev', age: 24, country: 'Uzbekistan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Taymuraz Tigiyev', age: 26, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Otar Tushishvili', age: 30, country: 'Georgia', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ruslan Tyumenbayev', age: 22, country: 'Kyrgyzstan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Armen Vardanian', age: 25, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Radoslav Velikov', age: 24, country: 'Bulgaria', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tonya Verbeek', age: 31, country: 'Canada', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wang Jiao', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adam Wheeler', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Agnieszka Wieszczek', age: 25, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Xu Li', age: 18, country: 'China', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yavor Yanakiev', age: 23, country: 'Bulgaria', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Saori Yoshida', age: 25, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kenichi Yumoto', age: 23, country: 'Japan', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Stanka Zlateva', age: 25, country: 'Bulgaria', year: 2008, date: '24/08/2008', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stephen Abas', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ara Abrahamian', age: 29, country: 'Sweden', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Khasan Baroyev', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mavlet Batyrov', age: 20, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Dokturishivili', age: 24, country: 'Uzbekistan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Seref Eroglu', age: 28, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iván Fundora', age: 28, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Karam Gaber', age: 24, country: 'Egypt', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rulon Gardner', age: 33, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Khadzhimurat Gatsalov', age: 21, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lise Golliot-Legrand', age: 27, country: 'France', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Anna Gomis', age: 30, country: 'France', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kyoko Hamaguchi', age: 26, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ali Reza Heidari', age: 28, country: 'Iran', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Magamed Ibragimov', age: 21, country: 'Uzbekistan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Chiharu Icho', age: 22, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kaori Icho', age: 20, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kenji Inoue', age: 27, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeong Ji-Hyeon', age: 21, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jamill Kelly', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Atryom Kyuregyan', age: 27, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gennady Laliyev', age: 25, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'István Majoros', age: 30, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vyacheslav Makarenko', age: 28, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gaydar Mamedaliyev', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mkhitar Manukyan', age: 31, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gyuzel Manyurova', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sara McMann', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Iryna Merleni-Mykulchyn', age: 22, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Patricia Miranda', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksey Mishin', age: 25, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roberto Monzón', age: 26, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Masoud Moustafa Gokar', age: 26, country: 'Iran', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mun Ui-Je', age: 29, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Makhach Murtazaliyev', age: 20, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'F?rid M?nsurov', age: 22, country: 'Azerbaijan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Armen Nazaryan', age: 30, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ramaz Nozadze', age: 20, country: 'Georgia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mehmet Özal', age: 30, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aydin Polatçi', age: 27, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yandro Quintana', age: 24, country: 'Cuba', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ali Reza Rezaei', age: 28, country: 'Iran', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Varteres Samurgashev', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cael Sanderson', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Buvaisa Saytiyev', age: 29, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sazhid Sazhidov', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chikara Tanabe', age: 29, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Artur Taymazov', age: 25, country: 'Uzbekistan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elbrus Tedieiev', age: 29, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Georgy Tsurtsumia', age: 23, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tonya Verbeek', age: 27, country: 'Canada', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Xu', age: 18, country: 'China', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marko Yli-Hannuksela', age: 30, country: 'Finland', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Saori Yoshida', age: 21, country: 'Japan', year: 2004, date: '29/08/2004', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Namiq Abdullayev', age: 29, country: 'Azerbaijan', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Filiberto Azcuy', age: 27, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sándor István Bárdosi', age: 23, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Serafim Barzakov', age: 25, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Islam Bayramukov', age: 29, country: 'Kazakhstan', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adem Bereket', age: 27, country: 'Turkey', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Terry Brands', age: 32, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yevhen Buslovych', age: 28, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: "Ak'ak'i Chachua", age: 31, country: 'Georgia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ali Reza Dabir', age: 23, country: 'Iran', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Debelka', age: 24, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rulon Gardner', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Arsen Gitinov', age: 23, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksey Glushkov', age: 25, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sammie Henson', age: 29, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mogamed Ibragimov', age: 26, country: 'Macedonia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniel Igali', age: 26, country: 'Canada', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jang Jae-Seong', age: 25, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: "Eldar K'urt'anidze", age: 28, country: 'Georgia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kang Yong-Gyun', age: 26, country: 'North Korea', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Amiran Kardanov', age: 24, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Murat Kardanov', age: 29, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksandr Karelin', age: 33, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kim In-Seop', age: 27, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Matt Lindland', age: 30, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mikael Ljungberg', age: 30, country: 'Sweden', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Garrett Lowney', age: 20, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Juan Luis Marén', age: 29, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lincoln McIlravy', age: 26, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mun Ui-Je', age: 25, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sagid Murtazaliyev', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'David Musulbes', age: 28, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Katsuhiko Nagata', age: 26, country: 'Japan', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Armen Nazaryan', age: 26, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lázaro Rivas', age: 25, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alexis Rodríguez', age: 22, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yoel Romero', age: 23, country: 'Cuba', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'David Saldadze', age: 22, country: 'Ukraine', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Varteres Samurgashev', age: 21, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adam Saytiyev', age: 22, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sheng Zetian', age: 27, country: 'China', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sim Gwon-Ho', age: 27, country: 'South Korea', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brandon Slay', age: 24, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Artur Taymazov', age: 21, country: 'Uzbekistan', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Murad Umakhanov', age: 23, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: "Mukhran Vakht'angadze", age: 27, country: 'Georgia', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hamza Yerlikaya', age: 24, country: 'Turkey', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marko Yli-Hannuksela', age: 26, country: 'Finland', year: 2000, date: '01/10/2000', sport: 'Wrestling', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ruslan Albegov', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sajjad Anoushiravani', age: 28, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Apti Aukhadov', age: 19, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Bartlomiej Bonk', age: 27, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iván Cambar', age: 28, country: 'Cuba', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zulfiya Chinshanlo', age: 19, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anatolii Cîrîcu', age: 23, country: 'Moldova', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Roxana Cocos', age: 23, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oscar Figueroa', age: 29, country: 'Colombia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christine Girard', age: 27, country: 'Canada', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hsu Shu-Ching', age: 21, country: 'Chinese Taipei', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ilya Ilyin', age: 24, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cristina Iovu', age: 19, country: 'Moldova', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eko Irawan', age: 23, country: 'Indonesia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Ivanov', age: 23, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yuliya Kalina', age: 23, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tatyana Kashirina', age: 21, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hripsime Khurshudyan', age: 25, country: 'Armenia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kim Un-Guk', age: 23, country: 'North Korea', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Irina Kulesha', age: 26, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Xueying', age: 22, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lin Qingfeng', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lu Haojie', age: 21, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lu Xiaojun', age: 28, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maiya Maneza', age: 26, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Razvan Martin', age: 20, country: 'Romania', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hiromi Miyake', age: 26, country: 'Japan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Navab Nasirshelal', age: 23, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Om Yun-Chol', age: 20, country: 'North Korea', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Svetlana Podobedova', age: 26, country: 'Kazakhstan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rim Jong-Sim', age: 19, country: 'North Korea', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kianoush Rostami', age: 21, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ryang Chun-Hwa', age: 21, country: 'North Korea', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Behdad Salimi', age: 22, country: 'Iran', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marina Shkermankova', age: 22, country: 'Belarus', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pimsiri Sirikaew', age: 22, country: 'Thailand', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oleksiy Torokhtiy', age: 26, country: 'Ukraine', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Triyatno', age: 24, country: 'Indonesia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Svetlana Tsarukayeva', age: 24, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wang Mingjuan', age: 26, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Wu Jingbiao', age: 23, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valentin Xristov', age: 18, country: 'Azerbaijan', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Zabolotnaya', age: 26, country: 'Russia', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhou Lulu', age: 24, country: 'China', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Adrian Zielinski', age: 23, country: 'Poland', year: 2012, date: '12/08/2012', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Khadzhimurat Akkayev', age: 23, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrey Aryamnov', age: 20, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cao Lei', age: 24, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Wei-Ling', age: 26, country: 'Chinese Taipei', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chen Xiexia', age: 25, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Yanqing', age: 29, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yevgeny Chigishev', age: 29, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vencelas Dabaya', age: 27, country: 'France', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gevorg Davtyan', age: 25, country: 'Armenia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nataliya Davydova', age: 23, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mariya Grabovetskaya', age: 21, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hoàng Anh Tu?n', age: 23, country: 'Vietnam', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ilya Ilyin', age: 20, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eko Irawan', age: 19, country: 'Indonesia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jang Mi-Ran', age: 24, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Prapawadee Jaroenrattanatarakoon', age: 24, country: 'Thailand', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dmitry Klokov', age: 25, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Olha Korobka', age: 22, country: 'Ukraine', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Szymon Kolecki', age: 26, country: 'Poland', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dmitry Lapikov', age: 26, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Hongli', age: 27, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liao Hui', age: 20, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Liu Chunhong', age: 25, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Long Qingquan', age: 17, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Lu Ying-Chi', age: 23, country: 'Chinese Taipei', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lu Yong', age: 22, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tigran G. Martirosyan', age: 20, country: 'Armenia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tigran V. Martirosyan', age: 25, country: 'Armenia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Irina Nekrasova', age: 20, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Anastasiya Novikova', age: 26, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'O Jong-Ae', age: 24, country: 'North Korea', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sibel Özkan', age: 20, country: 'Turkey', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pak Hyon-Suk', age: 23, country: 'North Korea', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Rybakov', age: 26, country: 'Belarus', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sa Jae-Hyeok', age: 23, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Diego Fernando Salazar', age: 27, country: 'Colombia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Viktors Šcerbatihs', age: 33, country: 'Latvia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marina Shainova', age: 22, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Oksana Slivenko', age: 21, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Matthias Steiner', age: 25, country: 'Germany', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Triyatno', age: 20, country: 'Indonesia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alla Vazhenina', age: 25, country: 'Kazakhstan', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nadezhda Yevstyukhina', age: 20, country: 'Russia', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Yoon Jin-Hee', age: 22, country: 'South Korea', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhang Xiangxiang', age: 25, country: 'China', year: 2008, date: '24/08/2008', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Khadzhimurat Akkayev', age: 19, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sedat Artuç', age: 28, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giorgi Asanidze', age: 28, country: 'Georgia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Batyushko', age: 22, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dmitry Berestov', age: 24, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Chen Yanqing', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Veliçko Çolakov', age: 22, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Pyrros Dimas', age: 32, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Milen Dobrev', age: 24, country: 'Bulgaria', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sergey Filimonov', age: 29, country: 'Kazakhstan', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jang Mi-Ran', age: 20, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wandee Kameaim', age: 26, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Zarema Kasayeva', age: 17, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Eszter Krutzler', age: 23, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Le Maosheng', age: 26, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lee Bae-Yeong', age: 24, country: 'South Korea', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Li Zhuo', age: 22, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Liu Chunhong', age: 21, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mabel Mosquera', age: 35, country: 'Colombia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Halil Mutlu', age: 31, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Oleg Perepechonov', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikolay Peshalov', age: 34, country: 'Croatia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gleb Pisarevsky', age: 28, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Udomporn Polsak', age: 22, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Valentina Popova', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ihor Razoronov', age: 34, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hossein Reza Zadeh', age: 26, country: 'Iran', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ri Song-Hui', age: 25, country: 'North Korea', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Israel José Rubio', age: 23, country: 'Venezuela', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Raema Lisa Rumbewas', age: 23, country: 'Indonesia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrey Rybakov', age: 22, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Taner Sagir', age: 19, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Viktors Šcerbatihs', age: 29, country: 'Latvia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Shi Zhiyong', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nataliya Skakun', age: 23, country: 'Ukraine', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tatyana Stukalova', age: 28, country: 'Belarus', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tang Gonghong', age: 25, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nurcan Taylan', age: 20, country: 'Turkey', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pawina Thongsuk', age: 25, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Eduard Tyukin', age: 26, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aree Wiratthaworn', age: 24, country: 'Thailand', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Agata Wróbel', age: 22, country: 'Poland', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Wu Meijin', age: 24, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nataliya Zabolotnaya', age: 19, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zhang Guozheng', age: 29, country: 'China', year: 2004, date: '29/08/2004', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Giorgi Asanidze', age: 25, country: 'Georgia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Galabin Boevski', age: 25, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Chemerkin', age: 28, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Chen Xiaomin', age: 23, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pyrros Dimas', age: 28, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ding Meiyuan', age: 20, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Cheryl Haworth', age: 17, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Marc Huster', age: 30, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Sri Indriyani', age: 21, country: 'Indonesia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Soraya Jiménez', age: 23, country: 'Mexico', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Akakios Kakiasvili', age: 31, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ioanna Khatziioannou', age: 26, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Szymon Kolecki', age: 18, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kuo Yi-Hang', age: 25, country: 'Chinese Taipei', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Lavrenov', age: 28, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Li Feng-Ying', age: 25, country: 'Chinese Taipei', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lin Weining', age: 21, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Karnam Malleswari', age: 25, country: 'India', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Georgi Markov', age: 22, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Erzsébet Márkus-Peresztegi', age: 31, country: 'Hungary', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Arsen Melikyan', age: 24, country: 'Armenia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Viktor Mitrou', age: 27, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Halil Mutlu', age: 27, country: 'Turkey', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tara Nott-Cunningham', age: 28, country: 'United States', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ruth Ogbeifo', age: 28, country: 'Nigeria', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gennady Oleshchuk', age: 24, country: 'Belarus', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikolay Peshalov', age: 30, country: 'Croatia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksey Petrov', age: 26, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Valentina Popova', age: 27, country: 'Russia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Hossein Reza Zadeh', age: 22, country: 'Iran', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ri Song-Hui', age: 21, country: 'North Korea', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Raema Lisa Rumbewas', age: 19, country: 'Indonesia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Leonidas Sabanis', age: 28, country: 'Greece', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Asaad Said Saif', age: 21, country: 'Qatar', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Winarni Binti Slamet', age: 24, country: 'Indonesia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Khassaraporn Suta', age: 28, country: 'Thailand', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Hossein Tavakoli', age: 22, country: 'Iran', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alan Tsagaev', age: 23, country: 'Bulgaria', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'María Isabel Urrutia', age: 35, country: 'Colombia', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ronny Weller', age: 31, country: 'Germany', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Agata Wróbel', age: 19, country: 'Poland', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Wu Wenxiong', age: 19, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Yang Xia', age: 22, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhan Xugang', age: 26, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Zhang Xiangxiang', age: 17, country: 'China', year: 2000, date: '01/10/2000', sport: 'Weightlifting', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Matteo Aicardi', age: 26, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Milan Aleksic', age: 26, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Betsey Armstrong', age: 29, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marta Bach', age: 19, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Samir Barac', age: 38, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gemma Beadsworth', age: 25, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Andrea Blas', age: 20, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Miho Boškovic', age: 29, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Victoria Brown', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ivan Buljubašic', age: 24, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Damir Buric', age: 31, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andro Bušlje', age: 26, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kami Craig', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nikša Dobud', age: 26, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Annika Dries', age: 20, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anna Espar', age: 19, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Laura Ester', age: 22, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maurizio Felugo', age: 31, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Pietro Figlioli', age: 28, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Filip Filipovic', age: 25, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Deni Fiorentini', age: 28, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Valentino Gallo', age: 27, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Maica García', age: 21, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Massimo Giacoppo', age: 29, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alex Giorgetti', age: 24, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Niccolò Gitto', age: 25, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Živko Gocic', age: 29, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kate Gynther', age: 30, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Igor Hinic', age: 36, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maro Jokovic', age: 24, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bronwen Knox', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Holly Lincoln-Smith', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Laura López', age: 24, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dušan Mandic', age: 18, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Courtney Mathewson', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alicia McCormack', age: 29, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ona Meseguer', age: 24, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Lorena Miranda', age: 21, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stefan Mitrovic', age: 24, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jane Moran', age: 27, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Petar Muslim', age: 24, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Slobodan Nikic', age: 29, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Paulo Obradovic', age: 26, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Mati Ortíz', age: 21, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Jenny Pareja', age: 28, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Giacomo Pastorino', age: 32, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Josip Pavic', age: 30, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Pilar Peña', age: 26, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Amaurys Perez', age: 36, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heather Petri', age: 34, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Duško Pijetlovic', age: 27, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Gojko Pijetlovic', age: 28, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Danijel Premuš', age: 31, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Christian Presciutti', age: 29, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrija Prlainovic', age: 25, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Glencora Ralph', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikola Raden', age: 27, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mel Rippon', age: 31, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kelly Rulon', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Aleksa Šaponjic', age: 20, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Melissa Seidemann', age: 22, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sophie Smith', age: 26, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Slobodan Soro', age: 33, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Ash Southern', age: 19, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jessica Steffens', age: 25, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Maggie Steffens', age: 19, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Sandro Sukno', age: 22, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Roser Tarragó', age: 19, country: 'Spain', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Stefano Tempesti', age: 33, country: 'Italy', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vanja Udovicic', age: 29, country: 'Serbia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Frano Vican', age: 36, country: 'Croatia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brenda Villa', age: 32, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Rowie Webster', age: 24, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lauren Wenger', age: 28, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elsie Windes', age: 27, country: 'United States', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nicola Zagame', age: 22, country: 'Australia', year: 2012, date: '12/08/2012', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Betsey Armstrong', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tony Azevedo', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ryan Bailey', age: 32, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Gemma Beadsworth', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Layne Beaubien', age: 32, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tibor Benedek', age: 36, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Péter Biros', age: 32, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brandon Brooks', age: 27, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Mieke Cabout', age: 22, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Patty Cardenas', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Aleksandar Ciric', age: 30, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Kami Craig', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Nikita Cuffe', age: 28, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Daniëlle de Bruijn', age: 30, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Filip Filipovic', age: 21, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Suzie Fraser', age: 19, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'István Gergely', age: 31, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Živko Gocic', age: 25, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Taniele Gofers', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Natalie Golda', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Alison Gregorka', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Rianne Guichelaar', age: 24, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Kate Gynther', age: 26, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Biurakn Hakhverdian', age: 22, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brittany Hayes', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Amy Hetzel', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jaime Hipp', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Norbert Hosnyánszky', age: 24, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Peter Hudnut', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tim Hutten', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tamás Kásás', age: 32, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gábor Kis', age: 25, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gergo Kiss', age: 30, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Noeki Klein', age: 25, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Bronwen Knox', age: 22, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Emma Knox', age: 30, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Simone Koot', age: 27, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'J. W. Krumpholz', age: 20, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Norbert Madaras', age: 28, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alicia McCormack', age: 25, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rick Merlo', age: 26, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tamás Molnár', age: 33, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Merrill Moses', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Branko Pekovic', age: 29, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Heather Petri', age: 30, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Duško Pijetlovic', age: 23, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jeff Powers', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Andrija Prlainovic', age: 21, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Nikola Raden', age: 23, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Bec Rippon', age: 29, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mel Rippon', age: 27, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jenna Santoromito', age: 21, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Mia Santoromito', age: 23, country: 'Australia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandar Šapic', age: 30, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dejan Savic', age: 33, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Denis Šefik', age: 31, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Alette Sijbring', age: 26, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Yasemin Smit', age: 23, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jesse Smith', age: 25, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Slobodan Soro', age: 29, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Jessica Steffens', age: 21, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Zoltán Szécsi', age: 30, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vanja Udovicic', age: 25, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Iefke van Belkum', age: 22, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gillian van den Berg', age: 36, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Marieke van den Ham', age: 25, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Ilse van der Meijden', age: 19, country: 'Netherlands', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Moriah Van Norman', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Peter Varellas', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Dániel Varga', age: 24, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dénes Varga', age: 21, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamás Varga', age: 33, country: 'Hungary', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Brenda Villa', age: 28, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Vlada Vujasinovic', age: 34, country: 'Serbia', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Lauren Wenger', age: 24, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Elsie Windes', age: 23, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Adam Wright', age: 31, country: 'United States', year: 2008, date: '24/08/2008', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Carmela Allucci', age: 34, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Alexandra Araujo', age: 32, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Dimitra Asilian', age: 32, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Roman Balashov', age: 27, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Robin Beauregard', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tibor Benedek', age: 32, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Péter Biros', age: 28, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Silvia Bosurgi', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Revaz Chomakhidze', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandar Ciric', age: 26, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Francesca Conti', age: 32, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tania Di Mario', age: 25, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Margaret Dingeldein', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Georgia Ellinaki', age: 30, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ellen Estes', age: 25, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Aleksandr Fedorov', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Rajmund Fodor', age: 28, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Jacqueline Frank', age: 24, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Sergey Garbuzov', age: 30, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'István Gergely', age: 27, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Elena Gigli', age: 19, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Vladimir Gojkovic', age: 23, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Natalie Golda', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Dmitry Gorshkov', age: 37, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Melania Grego', age: 31, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Danilo Ikodinovic', age: 27, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Viktor Jelenic', age: 33, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Predrag Jokic', age: 21, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Eftykhia Karagianni', age: 30, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Angeliki Karapataki', age: 29, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Tamás Kásás', age: 28, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Gergo Kiss', age: 26, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nikolay Kozlov', age: 32, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Voula Kozomboli', age: 30, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Georgia Lara', age: 24, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kiki Liosi', age: 24, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Ericka Lorenz', age: 23, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Norbert Madaras', age: 24, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Nikolay Maksimov', age: 31, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Giusi Malato', age: 33, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Antiopi Melidoni', age: 26, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Martina Miceli', age: 30, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Tamás Molnár', age: 29, country: 'Hungary', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Heather Moody', age: 30, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Tonia Moraiti', age: 27, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Evi Moraitidou', age: 29, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Thalia Munro', age: 22, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Maddalena Musumeci', age: 28, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Anthi Mylonaki', age: 20, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Slobodan Nikic', age: 21, country: 'Serbia and Montenegro', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Katerina Oikonomopoulou', age: 26, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Heather Petri', age: 26, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Cinzia Ragusa', age: 27, country: 'Italy', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 1, silver: 0, bronze: 0, total: 1, }, { athlete: 'Andrey Rekechinsky', age: 23, country: 'Russia', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, { athlete: 'Antigoni Roumbesi', age: 21, country: 'Greece', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 1, bronze: 0, total: 1, }, { athlete: 'Kelly Rulon', age: 20, country: 'United States', year: 2004, date: '29/08/2004', sport: 'Waterpolo', gold: 0, silver: 0, bronze: 1, total: 1, }, {