Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion documentation/ag-grid-docs/src/content/docs-nav/nav.json
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,15 @@
"type": "item",
"title": "Formulas",
"path": "formulas",
"isEnterprise": true
"isEnterprise": true,
"children": [
{
"type": "item",
"title": "Formula Editor",
"path": "formula-editor-component",
"isEnterprise": true
}
]
},
{
"type": "item",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ensureGridReady, test, waitForGridContent } from '@utils/grid/test-utils';

test.agExample(import.meta, () => {
test.eachFramework('Example', async ({ page }) => {
// PLACEHOLDER - MINIMAL TEST TO ENSURE GRID LOADS WITHOUT ERRORS
await ensureGridReady(page);
await waitForGridContent(page);
// END PLACEHOLDER
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div id="myGrid" style="height: 100%"></div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import type { ColDef, GetRowIdParams, GridApi, GridOptions, ValueFormatterParams } from 'ag-grid-community';
import {
ClientSideRowModelModule,
ModuleRegistry,
NumberEditorModule,
TextEditorModule,
ValidationModule,
createGrid,
} from 'ag-grid-community';
import { FormulaModule } from 'ag-grid-enterprise';

ModuleRegistry.registerModules([
ClientSideRowModelModule,
FormulaModule,
NumberEditorModule,
TextEditorModule,
ValidationModule,
]);

let gridApi: GridApi;

const valueFormatter = ({ value }: ValueFormatterParams) => `$ ${Number(value).toFixed(2)}`;
const getRowId = (params: GetRowIdParams) => String(params.data.id);

const columnDefs: ColDef[] = [
{ field: 'item' },
{ field: 'price', valueFormatter },
{ field: 'qty' },
{ field: 'total', allowFormula: true, cellEditor: 'agTextCellEditor', valueFormatter },
];

const gridOptions: GridOptions = {
columnDefs,
getRowId,
defaultColDef: {
editable: true,
flex: 1,
},
rowData: [
{
id: 1,
item: 'Apples',
price: 1.2,
qty: 4,
total: '=REF(COLUMN("price"),ROW(1))*REF(COLUMN("qty"),ROW(1))',
},
{
id: 2,
item: 'Bananas',
price: 0.5,
qty: 6,
total: '=REF(COLUMN("price"),ROW(2))*REF(COLUMN("qty"),ROW(2))',
},
{
id: 3,
item: 'Oranges',
price: 0.8,
qty: 3,
total: '=REF(COLUMN("price"),ROW(3))*REF(COLUMN("qty"),ROW(3))',
},
{
id: 4,
item: 'Pears',
price: 1.4,
qty: 2,
total: '=REF(COLUMN("price"),ROW(4))*REF(COLUMN("qty"),ROW(4))',
},
{
id: 5,
item: 'Grapes',
price: 2.1,
qty: 3,
total: '=REF(COLUMN("price"),ROW(5))*REF(COLUMN("qty"),ROW(5))',
},
{
id: 6,
item: 'Strawberries',
price: 1.8,
qty: 4,
total: '=REF(COLUMN("price"),ROW(6))*REF(COLUMN("qty"),ROW(6))',
},
],
};

document.addEventListener('DOMContentLoaded', () => {
const gridDiv = document.querySelector<HTMLElement>('#myGrid')!;
gridApi = createGrid(gridDiv, gridOptions);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ensureGridReady, test, waitForGridContent } from '@utils/grid/test-utils';

test.agExample(import.meta, () => {
test.eachFramework('Example', async ({ page }) => {
// PLACEHOLDER - MINIMAL TEST TO ENSURE GRID LOADS WITHOUT ERRORS
await ensureGridReady(page);
await waitForGridContent(page);
// END PLACEHOLDER
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div id="myGrid" style="height: 100%"></div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import type { ColDef, GetRowIdParams, GridApi, GridOptions, ValueFormatterParams } from 'ag-grid-community';
import {
ClientSideRowModelModule,
ModuleRegistry,
NumberEditorModule,
TextEditorModule,
ValidationModule,
createGrid,
} from 'ag-grid-community';
import { CellSelectionModule, FormulaModule } from 'ag-grid-enterprise';

ModuleRegistry.registerModules([
CellSelectionModule,
ClientSideRowModelModule,
FormulaModule,
NumberEditorModule,
TextEditorModule,
ValidationModule,
]);

let gridApi: GridApi;

const valueFormatter = ({ value }: ValueFormatterParams) => `$ ${Number(value).toFixed(2)}`;
const getRowId = (params: GetRowIdParams) => String(params.data.id);

const columnDefs: ColDef[] = [
{ field: 'item' },
{ field: 'price', valueFormatter },
{ field: 'qty' },
{ field: 'total', allowFormula: true, valueFormatter },
];

const gridOptions: GridOptions = {
columnDefs,
getRowId,
cellSelection: {
handle: {
mode: 'fill',
},
},
defaultColDef: {
editable: true,
flex: 1,
},
rowData: [
{
id: 1,
item: 'Apples',
price: 1.2,
qty: 4,
total: '=REF(COLUMN("price"),ROW(1))*REF(COLUMN("qty"),ROW(1))',
},
{
id: 2,
item: 'Bananas',
price: 0.5,
qty: 6,
total: '=REF(COLUMN("price"),ROW(2))*REF(COLUMN("qty"),ROW(2))',
},
{
id: 3,
item: 'Oranges',
price: 0.8,
qty: 3,
total: '=REF(COLUMN("price"),ROW(3))*REF(COLUMN("qty"),ROW(3))',
},
{
id: 4,
item: 'Pears',
price: 1.4,
qty: 2,
total: '=REF(COLUMN("price"),ROW(4))*REF(COLUMN("qty"),ROW(4))',
},
{
id: 5,
item: 'Grapes',
price: 2.1,
qty: 3,
total: '=REF(COLUMN("price"),ROW(5))*REF(COLUMN("qty"),ROW(5))',
},
{
id: 6,
item: 'Strawberries',
price: 1.8,
qty: 4,
total: '=REF(COLUMN("price"),ROW(6))*REF(COLUMN("qty"),ROW(6))',
},
],
};

document.addEventListener('DOMContentLoaded', () => {
const gridDiv = document.querySelector<HTMLElement>('#myGrid')!;
gridApi = createGrid(gridDiv, gridOptions);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: "Formula Editor Component"
enterprise: true
---
The Formula Cell Editor is the default editor for columns with `allowFormula: true`. It tokenises cell references, highlights ranges, and provides function autocomplete while you type.

## Default Formula Editor

If a column enables formulas and does not specify a `cellEditor`, the grid automatically uses the Formula Cell Editor.

{% gridExampleRunner title="Formula Editor" name="formula-editor-component" exampleHeight=320 /%}

{% note %}
Range highlights and range handle editing require `cellSelection` to be enabled. Without it, the editor still works but range highlights and handles are not shown.
{% /note %}

## Disabling Formulas Cell Editor

Providing a `cellEditor` opts the column out of the Formula Cell Editor. Formulas still evaluate, but range highlighting, handles, and function autocomplete are disabled because a different editor is in use.

{% gridExampleRunner title="Formula Editor Disabled" name="formula-editor-component-disabled" exampleHeight=320 /%}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import {
ValidationModule,
createGrid,
} from 'ag-grid-community';
import { FormulaModule } from 'ag-grid-enterprise';
import { CellSelectionModule, FormulaModule } from 'ag-grid-enterprise';

ModuleRegistry.registerModules([
CellSelectionModule,
ClientSideRowModelModule,
FormulaModule,
NumberEditorModule,
Expand Down Expand Up @@ -38,6 +39,11 @@ const gridOptions: GridOptions = {
editable: true,
flex: 1,
},
cellSelection: {
handle: {
mode: 'fill',
},
},
rowData: [
{
id: 1,
Expand Down
44 changes: 31 additions & 13 deletions documentation/ag-grid-docs/src/content/docs/formulas/index.mdoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ Formula strings can be provided to cells in the grid, allowing for dynamic calcu

To enable formulas, set the column property `allowFormula = true` on one or more columns and ensure that your rows have [Row IDs](./row-ids/#row-ids). In the example below, the values in columns Subtotal, Tax and Total are computed using formulas which can be modified by the end-user.

{% gridExampleRunner title="Formulas" name="formulas" exampleHeight=390 /%}

```{% frameworkTransform=true %}
const gridOptions = {
columnDefs: [
Expand All @@ -20,12 +18,31 @@ const gridOptions = {
{ field: 'tax', allowFormula: true },
{ field: 'total', allowFormula: true },
],
cellSelection: {
handle: {
mode: 'fill',
},
},
getRowId: (params) => String(params.data.rid),
}
```

When using formulas, the following features are enabled by default:
- [Row Numbers](./row-numbers/)
{% gridExampleRunner title="Formulas" name="formulas" exampleHeight=390 /%}


## Formula Editor Component

The Formula Cell Editor provides range highlighting, range handles, and function autocomplete while you edit formula-enabled
cells. It appears automatically for columns with `allowFormula: true` unless you supply a `cellEditor`. See
[Formula Editor Component](./formula-editor-component/) for behaviour details and how to disable it.

Range highlights and range handle editing require `cellSelection` to be enabled.

## Feature Interactions

When using formulas, the following feature integrations apply:
- [Fill Handle](./cell-selection-fill-handle/): Dragging to fill from a formula offsets relative references (for example `=B1+C2` becomes `=B2+C3` on the next row). Absolute references (`$A$1`, `A$1`, `$A1`) remain fixed.
- [Row Numbers](./row-numbers/): Enabled by default.

Certain features do not work in conjunction with formulas:
- [Cell Expressions](./cell-expressions/#cell-expressions)
Expand All @@ -51,15 +68,13 @@ Constants can be numbers (e.g. `3.14`, `42`, `-7`), strings (e.g. `"Hello"`, `"W

### Cell references

Cell references are used to refer to the value of another cell in the grid and are symbolised by an alphabetical column identifier followed by a numerical row identifier.
Cell references are used to refer to the value of another cell in the grid and are symbolised by an alphabetical column identifier followed by a numerical row identifier (e.g. `A1`).
After the 26th column, the columns continue with two letters (e.g. AA, AB, AC, etc.). Rows are numbered starting from 1.

{% note %}
Column letters are assigned for every column in the grid, including columns that are hidden or not displayed due to column groups being collapsed.
{% /note %}

Formulas can reference other cells using their column letter and row number. Columns are labelled alphabetically (A, B, C, ..., Z, AA, AB, etc.), and rows are numbered starting from 1.

Examples of cell references:
- `=A1` refers to the cell in column A, row 1.
- `=B2` refers to the cell in column B, row 2.
Expand All @@ -71,13 +86,12 @@ To instead always refer to the same position, use absolute references by prefixi
- `=$A1` always refers to column A, but the row can change.

#### Long-Form References
When saving cell references, the grid converts these into a long hand format using column and row IDs to ensure that changes in the source data allow the grid to continue to refer to the correct cells when the data changes without
the grid being open.
When saving cell references, the grid converts these into a long-hand format using column and row IDs. This ensures the formula continues to refer to the correct cells even if rows or columns move while the grid is not open.

For example, if the column with ID `athlete` is in column A, and the row with ID `a` is in row 1, then the formula `=A1` becomes `=REF(COLUMN('athlete'), ROW('a'))`.
When this is a static reference, for example $A$1, the long hand format uses A and 1 in place of IDs, but adds a true to indicate the value is absolute (e.g `=$A$1` becomes `=REF(COLUMN('a', true), ROW('1', true))`).
When this is a static reference, for example `$A$1`, the long-hand format uses A and 1 in place of IDs but adds `true` to indicate the value is absolute (e.g. `=$A$1` becomes `=REF(COLUMN('a', true), ROW('1', true))`).

This long hand format can be used directly in your data source or application via a valueGetter, and will be converted to the short hand format when the user opens a cell editor.
This long-hand format can be used directly in your data source or application via a `valueGetter`, and will be converted to the shorthand format when the user opens a cell editor.

{% note %}
As cell formulas are not immediately parsed when the grid opens, we suggest using the long hand format when providing formulas directly in your data source or application as any row positional changes may impact the relative cell when resolved.
Expand Down Expand Up @@ -267,7 +281,7 @@ Formulas can be stored outside of the grid's `rowData` by providing a `formulaDa

The snippet and example below illustrate an example of storing formulae in a `Map` object, external to the grid.

In the example, the "Total" column contains editable formulas which are stored in an external `Map`. The contents of the map and the row data can be visualised with the provided buttons.
In the example, the "Total" column contains editable formulas which are stored in an external `Map`. The contents of the map and the row data can be visualised with the provided buttons. This example intentionally omits `cellSelection` to show that formulas work without range highlights.

```{% frameworkTransform=true %}
const gridOptions = {
Expand Down Expand Up @@ -297,7 +311,7 @@ const gridOptions = {

{% gridExampleRunner title="Formula Data Source" name="formulas-formula-data-source" exampleHeight=440 /%}

A user provided datasource should provide the following interface:
A user-provided data source should provide the following interface:

{% interfaceDocumentation interfaceName="FormulaDataSource" config={ "description": "" } /%}

Expand Down Expand Up @@ -367,3 +381,7 @@ When performing an [Excel Export](./excel-export), the grid will export the form
| `COUNTA(arg1, arg2, ...)` | Returns the count of non-empty values among the arguments. |
| `COUNTBLANK(arg1, arg2, ...)` | Returns the count of empty values among the arguments. |
| `COUNTIF(range, criteria)` | Returns the count of values in the range that meet the criteria. |

## Next Up

Continue to the next section: [Formula Editor Component](./formula-editor-component/).
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The grid comes with some cell editors provided out of the box. These cell editor
* [Large Text Cell Editor](./provided-cell-editors-large-text/)
* [Select Cell Editor](./provided-cell-editors-select/)
* [Rich Select Cell Editor](./provided-cell-editors-rich-select/) {% enterpriseIcon /%}
* [Formula Cell Editor](./formula-editor-component/) {% enterpriseIcon /%}

There are also some additional cell editors that are generally used with [Cell Data Types](./cell-data-types/):

Expand Down
Loading
Loading