"Description": "Learn how to use the ABP Dynamic Form Module to create dynamic, configurable forms with validation, conditional logic, and custom components in Angular applications."
"Description": "Learn how to use the ABP Dynamic Form Module to create dynamic, configurable forms with validation, conditional logic, nested groups and arrays, many input types, and custom components in Angular applications."
}
```
@ -126,12 +126,27 @@ interface FormFieldConfig {
placeholder?: string; // Placeholder text
required?: boolean; // Whether the field is required
disabled?: boolean; // Whether the field is disabled
options?: OptionProps; // Options for select fields
options?: OptionProps; // Options for select/radio (static or API)
validators?: ValidatorConfig[]; // Array of validator configurations
conditionalLogic?: ConditionalRule[]; // Array of conditional rules
Used for `select` and `radio` fields. Provide either static `defaultValues` or `url` for API-driven options:
```ts
interface OptionProps<T=any> {
defaultValues?: T[]; // Static array of options
url?: string; // API endpoint URL
url?: string; // API endpoint URL (fetched via RestService)
disabled?: (option: T) => boolean; // Function to disable specific options
labelProp?: string; // Property name for label
valueProp?: string; // Property name for value
apiName?: string; // API name for RestService
labelProp?: string; // Property name for label (default 'value')
valueProp?: string; // Property name for value (default 'key')
apiName?: string; // API name for RestService when using url
}
```
When using `url`, the response array is mapped with `valueProp` / `labelProp` to build options. Localization is applied to labels via `abpLocalization` where applicable.
## Conditional Logic
The Dynamic Form Module supports conditional logic to show/hide or enable/disable fields based on other field values:
Groups use `<fieldset>` / `<legend>` for semantics and accessibility. Nesting is recursive (groups inside groups).
### Array Type
Use `type: 'array'` for dynamic lists with add/remove (e.g. phone numbers, work experience). Set `children` for each item schema, and optionally `minItems` / `maxItems`:
Arrays render add/remove buttons, item labels (e.g. "Phone Number #1"), and respect `minItems` / `maxItems`. You can nest groups inside arrays and arrays inside groups.
See `NESTED-FORMS.md` in the package and `apps/dev-app/src/app/dynamic-form-page` for more examples.
## Custom Components
You can use custom components for specific fields by providing a component that implements `ControlValueAccessor`:
@ -575,6 +675,18 @@ export class MyComponent {
}
```
## Accessibility
The Dynamic Form includes built-in accessibility support:
- **ARIA attributes**: `aria-label`, `aria-required`, `aria-invalid`, `aria-describedby`, `aria-busy` on inputs and actions; `role="form"`, `role="group"`, `role="radiogroup"`, `role="alert"` where appropriate.
- **Error handling**: Validation errors are exposed via `aria-describedby` and `aria-live="polite"` so screen readers announce them.
- **Focus management**: On submit when the form is invalid, focus moves to the first invalid field and it scrolls into view.
- **Keyboard navigation**: All controls are keyboard-accessible; range and color inputs use appropriate ARIA value attributes.
When using custom components or projected actions, keep labels, error associations, and focus behavior consistent for a good experience.
## Complete Example
Here's a complete example demonstrating various features:
@ -799,15 +911,17 @@ export class EmployeeFormComponent {
### DynamicFormService
The `DynamicFormService` provides utility methods for form management:
The `DynamicFormService` provides utility methods for form management. It is `providedIn: 'root'`.
#### Methods
| Method | Parameters | Returns | Description |
|--------|-----------|---------|-------------|
| `createFormGroup(fields)` | `FormFieldConfig[]` | `FormGroup` | Creates a FormGroup from field configurations |
| `createFormGroup(fields)` | `FormFieldConfig[]` | `FormGroup` | Creates a FormGroup from field configurations (handles `group` / `array` recursively) |
| `getInitialValues(fields)` | `FormFieldConfig[]` | `any` | Extracts initial values from field configurations |
| `getOptions(url, apiName?)` | `string, string?` | `Observable<any[]>` | Fetches options from an API endpoint |
| `getOptions(url, apiName?)` | `string, string?` | `Observable<any[]>` | Fetches options from an API via `RestService`; used for `select` / `radio` when `options.url` is set |
Nested forms use `DynamicFormGroupComponent` and `DynamicFormArrayComponent` internally. You configure them via `type: 'group'` / `type: 'array'` and `children`; you do not need to use these components directly.