import { Meta } from "@storybook/addon-docs";

<Meta title="Component Library/Async Actions/In Forms/Documentation" />

# Async Actions In Forms

These directives should be used when building forms with buttons that trigger long running tasks in the background,
eg. Submit or Delete buttons. For buttons that are not associated with a form see [Standalone Async Actions](?path=/story/component-library-async-actions-standalone-documentation--page).

There are two separately supported use-cases: Submit buttons and standalone form buttons (eg. Delete buttons).

## Usage: Submit buttons

Adding async actions to submit buttons requires the following 3 steps

### 1. Add a handler to your `Component`

A handler is a function that returns a promise or an observable. Functions that return `void` are also supported which is
useful for aborting an action.

**NOTE:**

- Defining the handlers as arrow-functions assigned to variables is mandatory if the handler needs access to the parent
  component using the variable `this`.
- `formGroup.invalid` will always return `true` after the first `await` operation, event if the form is not actually
  invalid. This is due to the form getting disabled by the `bitSubmit` directive while waiting for the async action to complete.

```ts
@Component({...})
class Component {
  formGroup = this.formBuilder.group({...});

  // submit can also return Observable instead of Promise
  submit = async () => {
    if (this.formGroup.invalid) {
      return;
    }

    await this.cryptoService.encrypt(/* ... */);

    // `formGroup.invalid` will always return `true` here

    await this.apiService.post(/* ... */);
  }
}
```

### 2. Add directive to the `form` element

Add the `bitSubmit` directive and supply the handler defined in step 1.

**NOTE:** The `directive` is defined using the input syntax: `[input]="handler"`.
This is different from how submit handlers are usually defined with the output syntax `(ngSubmit)="handler()"`.

```html
<form [formGroup]="formGroup" [bitSubmit]="submit">...</form>
```

### 3. Add directive to the `type="submit"` button

Add both `bitButton` and `bitFormButton` directives to the button.

```html
<button type="submit" bitButton bitFormButton>{{ "submit" | i18n }}</button>
```

## Usage: Standalone form buttons

Adding async actions to standalone form buttons requires the following 3 steps.

### 1. Add a handler to your `Component`

A handler is a function that returns a promise or an observable. Functions that return `void` are also supported which is
useful for aborting an action.

**NOTE:** Defining the handlers as arrow-functions assigned to variables is mandatory if the handler needs access to the parent
component using the variable `this`.

```ts
@Component({...})
class Component {
  formGroup = this.formBuilder.group({...});

  submit = async () => {
    // not relevant for this example
  }

  // action can also return Observable instead of Promise
  handler = async () => {
    if (/* perform guard check */) {
      return;
    }

    await this.apiService.post(/* ... */);
  };
}
```

### 2. Add directive to the `form` element

The `bitSubmit` directive is required beacuse of its coordinating role.

```html
<form [formGroup]="formGroup" [bitSubmit]="submit">...</form>
```

### 3. Add directives to the `button` element

Add `bitButton`, `bitFormButton`, `bitAction` directives to the button. Make sure to supply a handler.

```html
<button type="button" bitFormButton bitButton [bitAction]="handler">Do action</button>
<button type="button" bitFormButton bitIconButton="bwi-star" [bitAction]="handler"></button>
```
