# Form

{% hint style="success" %}
This is the official documentation of Forest Admin Cloud.
{% endhint %}

Frequently, it is necessary to request information before proceeding with the execution of an action. In Forest Admin, this occurs through a form that pops up before the action is executed. For example, you might need to explain why you need to block a user account or decide how much to charge a user's credit card.

### TL;DR

Ensure you update the collection and action names as needed.

{% code title="index.ts" %}

```typescript
import type { Agent } from '@forestadmin/forest-cloud';
import { Schema } from '../typings';

export default function customizeAgent(agent: Agent<Schema>) {
  agent.customizeCollection('users', collection =>
    collection.addAction('A sample action', {
      scope: 'Single',
      form: [{
        label: 'field',
        description: 'some description...',
        type: 'String',
      }],
      execute: async (context) => {
        const { field } = context.formValues;
        // Your business logic here.
      },
    }),
  );
}
```

{% endcode %}

***

{% hint style="info" %}
To make the code easier to read, all the code snippets below should be wrapped in the following code. Ensure you update the collection and action names as needed.

```typescript
import type { Agent } from '@forestadmin/forest-cloud';
import { Schema } from '../typings';

export default function customizeAgent(agent: Agent<Schema>) {
  agent.customizeCollection('contacts', collection =>
    collection.addAction('Ban contact', {
      scope: 'Single',
      // Insert the code snippet here.
    }),
  );
}
```

{% endhint %}

### Creating a static form

Add the `form` key in the action definition to open a form before executing the action:

```typescript
form: [{
  label: 'reason',
  type: 'String',
}],
```

<figure><img src="/files/W2ovdRj29Mh17OPYxan9" alt=""><figcaption></figcaption></figure>

Arguments:

* Form *<mark style="color:green;">\[Object]</mark>*: A JavaScript array that contains a list of JavaScript Objects, each representing a field to add in the form.
  * `label`<mark style="color:red;">\*</mark> *<mark style="color:green;">String</mark>*: The name of the field.
  * `type`<mark style="color:red;">\*</mark> *<mark style="color:green;">String</mark>*: The type of the field. Expected value:
    * *<mark style="color:green;">Boolean</mark>*
    * *<mark style="color:green;">Date</mark>*
    * *<mark style="color:green;">Dateonly</mark>*
    * *<mark style="color:green;">Enum</mark>*
    * *<mark style="color:green;">Json</mark>*
    * *<mark style="color:green;">Number</mark>*
    * *<mark style="color:green;">NumberList</mark>*
    * *<mark style="color:green;">EnumList</mark>*
    * *<mark style="color:green;">String</mark>*
    * *<mark style="color:green;">StringList</mark>*
    * *<mark style="color:green;">File</mark>*
    * *<mark style="color:green;">FileList</mark>*
    * *<mark style="color:green;">Collection</mark>: See* [#configuring-a-relationship-as-a-form-field](#configuring-a-relationship-as-a-form-field "mention")
  * `collectionName` *<mark style="color:green;">String</mark>*: **Required** when `type` is *<mark style="color:green;">Collection</mark>*.
  * `defaultValue`<mark style="color:green;">any</mark>: Set the default value of the field.
  * `description` *<mark style="color:green;">String</mark>*: A description that explains the field's function and usage for clarity.
  * `enumValues` *<mark style="color:green;">\[String]</mark>*: **Required** when `type` is *<mark style="color:green;">Enum</mark>*.
  * `isReadOnly`<mark style="color:green;">Boolean</mark>: Specifies whether the field is mandatory or not. Default false.
  * `isRequired` *<mark style="color:green;">Boolean</mark>*: Specifies whether the field is mandatory or not. Default false.
  * `widget` *<mark style="color:green;">String</mark>*: Customize the widget to display the field.

### Creating a dynamic form

To create a form that changes based on the values of other fields, use a function instead of a static value for properties that support dynamic values. Both synchronous and asynchronous functions are supported. These functions have the same [`context`](/cloud/code-customization/actions/context.md) argument as the `execute()` function.

Properties that support dynamic values:

* `isRequired`
* `isReadOnly`
* `defaultValue`
* `description`
* `enumValues` if type is `Enum`
* `collectionName` if type is `Collection`

When setting up a dynamic form, you can use two additional properties:

* `if`: Display the field if the condition is met.
* `value`: Sets the field's current value.

Widgets properties that support dynamic values:

* `options`
* `min`
* `max`
* `step`

### **Retrieving form values**

Within the `execute()` function, you can access and use the form input values provided by the user who initiated the action by accessing the `formValues` attribute from the context.

```typescript
execute: async (context) => {
  const { reason } = context.formValues;
},
```

### Examples

{% hint style="info" %}
To make the code easier to read, all the code snippets below should be wrapped in the following code. Ensure you update the collection and action names as needed.

```typescript
import type { Agent } from '@forestadmin/forest-cloud';
import { Schema } from '../typings';

export default function customizeAgent(agent: Agent<Schema>) {
  agent.customizeCollection('contacts', (collection) => {
    // Insert the code snippet here.
  });
}
```

{% endhint %}

#### **Configuring a Relationship as a Form Field**

When you use the `Collection` type, you can link to any record from any collection. This link uses the record's primary key as its value.

{% hint style="info" %}
The value is stored in an array to handle composite primary keys. For non-composite keys, the array contains one value.
{% endhint %}

```typescript
collection.addAction('Assign ticket', {
  scope: 'Single',
  form: [{
    label: 'Assignee',
    description: 'The user to assign the ticket to',
    type: 'Collection',
    collectionName: 'user',
    isRequired: true,
  }],
  execute: async (context, resultBuilder) => {
    const [userId] = context.formValues.Assignee;
    // ...
  },
});
```

<figure><img src="/files/2PmN1z3fF4pIjrbXMNA4" alt=""><figcaption></figcaption></figure>

#### **Making a field required dynamically**

In this example, we request to fill the reason field if the amount of the credit card charge exceeds 1000.

```typescript
collection.addAction('Charge credit card', {
  scope: 'Single',
  form: [{
    label: 'amount',
    type: 'Number',
    isRequired: true,
  }, {
    label: 'reason',
    type: 'String',
    isRequired: context => context.formValues['amount'] > 1000,
  }],
  execute: async (context) => {
    // ...
  },
});
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forestadmin.com/cloud/code-customization/actions/form.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
