# Custom expression functions

> Add your own functions to the NGX View Builder expression language from your Angular app, including async functions that call your API.

Source: https://ngxviewbuilder.io/developers/custom-functions

Creators write expressions like `isEmpty({email})`. You can add your own functions so they can write `vatAmount({netPrice})` or `isWorkday({date})`.

## Registration

```ts
import { provideNgxViewBuilderExtensions, IJexlFunctionRegistration } from '@ngxviewbuilder/runtime';

const functions: IJexlFunctionRegistration[] = [
  {
    name: 'vatAmount',
    args: ['net', 'rate(optional)'],
    description: 'Net price + VAT (default 21%)',
    example: 'vatAmount({netPrice})',
    handler: (net: unknown, rate?: unknown) =>
      Number(net || 0) * (1 + (Number(rate) || 0.21)),
  },
  {
    name: 'formatIban',
    args: ['iban'],
    description: 'Groups an IBAN into blocks of 4',
    example: 'formatIban({accountNumber})',
    handler: (iban: unknown) =>
      String(iban ?? '').replace(/\s+/g, '').replace(/(.{4})/g, '$1 ').trim(),
  },
];

providers: [
  provideNgxViewBuilderExtensions({ expressionFunctions: functions }),
]
```

Or at runtime: `api.registerExpressionFunction(fn)` / `api.registerExpressionFunctions(fns)`.

## Registration fields

| Field | Purpose |
| --- | --- |
| `name` | The identifier used in expressions (re-registering a name replaces it) |
| `handler` | The implementation. May return a value or a `Promise` |
| `args` | Argument names, shown in the expression editor's help |
| `description` / `example` | Shown in the editor's function list. Write them well; creators rely on this |

Custom functions are flagged `isCustom` and appear alongside the [built-ins](https://ngxviewbuilder.io/creators/functions) in the editor's help panel.

## Async functions

Handlers may be async (the built-in `runDataSource` is). Note that *synchronous* evaluation contexts (e.g. inline default-value evaluation) skip expressions containing async functions, so keep functions used in `defaultValue` synchronous.

## Guidelines

- **Be forgiving with inputs.** Creators will pass empty strings and `null`, so coerce (`Number(x) || 0`, `String(x ?? '')`) instead of throwing. A thrown error silently fails the whole expression.
- **Return simple types** (string, number, boolean, array, plain object) that JSON-serialise cleanly.
- **Keep them pure** where possible. Functions with side effects (like `setElementProperty`) are powerful but make views harder to reason about.
- **Namespace by convention** if you register many: `acmeVat()`, `acmeRound()`. Function names are global.
