# Action Column Forms

Canonical page: https://www.adaptabletools.com/docs/handbook-action-column-form

- A `form` Control opens an [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) in a popover
- It is the same Form used in Alerts, Export Destinations, Data Sets and Custom Toolbars
- `getInitialData` seeds the fields from the row
- Form buttons receive `context.formData` plus the Action Column context

A `form` Control is for editing a few related fields without leaving the grid — counts, a status change, a short comment.

The `form` property is a standard [`AdaptableForm`](https://www.adaptabletools.com/docs/reference/adaptableform.md) — the same object used for Alert messages, Custom Export Destinations, Data Sets and Custom Toolbar forms. See [Adaptable Forms](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) for full details on titles, fields, validation and buttons.

Use `getInitialData` to seed those fields from the row. Form buttons receive `context.formData` plus the Action Column context, so they can write back to the row.

### Defining a Form Control

Put the Column in `actionColumnOptions.actionColumns`.

Supply `columnId` and an optional `friendlyName`.

Set `type` to `'form'`. `label` and `icon` become the trigger that opens the popover.

`getInitialData` copies values from the current row into the Form fields.

`form.fields` is a standard [`AdaptableForm`](https://www.adaptabletools.com/docs/reference/adaptableform.md) field list.

Form buttons receive `context.formData` and can write back to the row.

```ts [[1, 1, "actionColumnOptions"], [1, 2, "actionColumns"], [2, 4, "columnId"], [2, 5, "friendlyName"], [3, 8, "type"], [3, 9, "label"], [4, 11, "getInitialData"], [5, 19, "fields"], [6, 25, "buttons"]]
actionColumnOptions: {
  actionColumns: [
    {
      columnId: 'edit_counts',
      friendlyName: 'Counts',
      controls: [
        {
          type: 'form',
          label: 'Edit',
          icon: {name: 'edit'},
          getInitialData: (context) => ({
            open_issues_count: context.data.open_issues_count,
            closed_issues_count: context.data.closed_issues_count,
            open_pr_count: context.data.open_pr_count,
            closed_pr_count: context.data.closed_pr_count,
          }),
          form: {
            title: 'Edit counts',
            fields: [
              {name: 'open_issues_count', label: 'Open Issues', fieldType: 'number'},
              {name: 'closed_issues_count', label: 'Closed Issues', fieldType: 'number'},
              {name: 'open_pr_count', label: 'Open PRs', fieldType: 'number'},
              {name: 'closed_pr_count', label: 'Closed PRs', fieldType: 'number'},
            ],
            buttons: [
              {
                label: 'Save',
                onClick: (_button, context) => {
                  [
                    'open_issues_count',
                    'closed_issues_count',
                    'open_pr_count',
                    'closed_pr_count',
                  ].forEach((field) => {
                    context.rowNode.setDataValue(
                      field,
                      Number(context.formData[field])
                    );
                  });
                },
              },
            ],
          },
        },
      ],
    },
  ],
},
```

**Example: Action Columns: Form**

Form popover that edits issue and PR counts

- `Counts` opens a Form seeded from Open / Closed Issues and Open / Closed PRs
- Save writes the four values back to the row

Demo project (Vanilla); the files without a marker are shown below:

```text
src/
  adaptableOptions.ts
  agGridModules.ts     [template]
  columnDefs.ts        [template]
  gridOptions.ts       [template]
  index.ts             [template]
  onAdaptableReady.ts  [template]
  rowData.ts           [template]
  styles.css           [template]
index.html             [template]
package.json           [template]
tsconfig.json          [template]
```

Files marked `[template]` are the same in every demo; see the [demo template](https://www.adaptabletools.com/llms/demo-template.md#vanilla).

**`src/adaptableOptions.ts`**

```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from './rowData';

const COUNT_FIELDS = [
  'open_issues_count',
  'closed_issues_count',
  'open_pr_count',
  'closed_pr_count',
] as const;

export const adaptableOptions: AdaptableOptions<WebFramework> = {
  primaryKey: 'id',
  adaptableId: 'Action Column Form',
  actionColumnOptions: {
    actionColumns: [
      {
        columnId: 'edit_counts',
        friendlyName: 'Counts',
        settings: {width: 100, suppressMenu: true},
        controls: [
          {
            type: 'form',
            label: 'Edit',
            icon: {name: 'edit'},
            getInitialData: context => ({
              open_issues_count: context.data?.open_issues_count ?? 0,
              closed_issues_count: context.data?.closed_issues_count ?? 0,
              open_pr_count: context.data?.open_pr_count ?? 0,
              closed_pr_count: context.data?.closed_pr_count ?? 0,
            }),
            form: {
              title: 'Edit counts',
              fields: [
                {
                  name: 'open_issues_count',
                  label: 'Open Issues',
                  fieldType: 'number',
                },
                {
                  name: 'closed_issues_count',
                  label: 'Closed Issues',
                  fieldType: 'number',
                },
                {
                  name: 'open_pr_count',
                  label: 'Open PRs',
                  fieldType: 'number',
                },
                {
                  name: 'closed_pr_count',
                  label: 'Closed PRs',
                  fieldType: 'number',
                },
              ],
              buttons: [
                {
                  label: 'Save',
                  buttonStyle: {variant: 'raised', tone: 'success'},
                  onClick: (_button, context: any) => {
                    COUNT_FIELDS.forEach(field => {
                      context.rowNode?.setDataValue(
                        field,
                        Number(context.formData[field])
                      );
                    });
                  },
                },
              ],
            },
          },
        ],
      },
    ],
  },
  initialState: {
    Theme: {CurrentTheme: 'dark'},
    Layout: {
      CurrentLayout: 'Standard Layout',
      Layouts: [
        {
          Name: 'Standard Layout',
          TableColumns: [
            'name',
            'language',
            'open_issues_count',
            'closed_issues_count',
            'open_pr_count',
            'closed_pr_count',
            'edit_counts',
          ],
          AutoSizeColumns: true,
        },
      ],
    },
  },
};
```
