{"id":13671048,"url":"https://github.com/udos86/ng-dynamic-forms","last_synced_at":"2025-05-14T14:07:42.198Z","repository":{"id":41562649,"uuid":"60208434","full_name":"udos86/ng-dynamic-forms","owner":"udos86","description":"Rapid form development library for Angular","archived":false,"fork":false,"pushed_at":"2024-02-06T11:28:40.000Z","size":9099,"stargazers_count":1316,"open_issues_count":128,"forks_count":372,"subscribers_count":70,"default_branch":"master","last_synced_at":"2025-05-09T01:03:49.598Z","etag":null,"topics":["angular","bootstrap","dynamic-forms","forms","foundation","ionic","kendo-ui","material","ng-bootstrap","ngx-bootstrap","primeng"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/udos86.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-06-01T20:26:33.000Z","updated_at":"2025-03-21T21:04:40.000Z","dependencies_parsed_at":"2023-02-01T04:00:59.292Z","dependency_job_id":"5b3b7f1c-d2a4-495e-9ed6-648df8908d06","html_url":"https://github.com/udos86/ng-dynamic-forms","commit_stats":{"total_commits":1555,"total_committers":32,"mean_commits":48.59375,"dds":0.07202572347266878,"last_synced_commit":"da1742ce051af5cebdcf905b189ab6b55fe365d7"},"previous_names":["udos86/ng2-dynamic-forms"],"tags_count":142,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/udos86%2Fng-dynamic-forms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/udos86%2Fng-dynamic-forms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/udos86%2Fng-dynamic-forms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/udos86%2Fng-dynamic-forms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/udos86","download_url":"https://codeload.github.com/udos86/ng-dynamic-forms/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254159194,"owners_count":22024558,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","bootstrap","dynamic-forms","forms","foundation","ionic","kendo-ui","material","ng-bootstrap","ngx-bootstrap","primeng"],"created_at":"2024-08-02T09:00:56.912Z","updated_at":"2025-05-14T14:07:42.180Z","avatar_url":"https://github.com/udos86.png","language":"TypeScript","readme":"# NG Dynamic Forms\n\n[![npm version](https://badge.fury.io/js/%40ng-dynamic-forms%2Fcore.svg)](https://badge.fury.io/js/%40ng-dynamic-forms%2Fcore)\n[![CI](https://github.com/udos86/ng-dynamic-forms/workflows/NG%20Dynamic%20Forms%20CI/badge.svg)](https://github.com/udos86/ng-dynamic-forms/actions)\n[![codecov](https://codecov.io/gh/udos86/ng-dynamic-forms/branch/master/graph/badge.svg)](https://codecov.io/gh/udos86/ng-dynamic-forms)\n[![DeepScan Grade](https://deepscan.io/api/projects/562/branches/912/badge/grade.svg)](https://deepscan.io/dashboard/#view=project\u0026pid=562\u0026bid=912)\n[![Downloads](http://img.shields.io/npm/dm/@ng-dynamic-forms/core.svg)](https://npmjs.org/package/@ng-dynamic-forms/core)\n\n***\n\nNG Dynamic Forms is a **rapid form development library** based on the official Angular\n[**dynamic forms guide**](https://angular.io/docs/ts/latest/cookbook/dynamic-form.html).\n\nIt **fully automates form UI creation** by introducing a set of maintainable **form control models** and **dynamic form control components** \n\n**Out of the box support** is provided for all popular UI libraries including **[Material](https://material.angular.io/)**, **[ngx-bootstrap](https://valor-software.com/ngx-bootstrap/#/)**, **[NG Bootstrap](https://ng-bootstrap.github.io/#/home)**, **[Foundation](http://foundation.zurb.com/)**, **[Ionic](http://ionicframework.com/)** and **[PrimeNG](http://www.primefaces.org/primeng/#/)**.\n                                                                                          \nExplore the [**live sample**](http://ng2-dynamic-forms.udos86.de/sample/index.html) and the [**API documentation**](http://ng2-dynamic-forms.udos86.de/docs/index.html)!\n\n## Table of Contents\n\n- [Getting Started](#getting-started)\n- [Running the Sample](#running-the-sample)\n- [Basic Usage](#basic-usage)\n- [UI Modules](#ui-modules)\n- [Form Groups](#form-groups)\n- [Form Arrays](#form-arrays)\n- [Form Layouts](#form-layouts)\n- [Form Control Configuration](#form-control-configuration)\n- [Form Control Events](#form-control-events)\n- [Updating Form Controls](#updating-form-controls)\n- [Custom Templates](#custom-templates)\n- [Custom Validators](#custom-validators)\n- [Custom Form Controls](#custom-form-controls)\n- [Validation Messaging](#validation-messaging)\n- [Related Form Controls](#related-form-controls)\n- [JSON Export \u0026 Import](#json-export--import)\n- [JSON Form Models](#json-form-models)\n- [Text Masks](#text-masks)\n- [Autocompletion](#autocompletion)\n- [FAQ](#faq)\n- [Appendix](#appendix)\n\n\n## Getting Started\n\n**1. Install the core package**:\n```\nnpm i @ng-dynamic-forms/core -S\n```\n  \n**2. Install a [UI package](#ui-modules) and its peer dependencies**:\n```\nnpm i @ng-dynamic-forms/ui-material -S\n```\n\n\n## Running the Sample\n\n**1. Clone the Git repository**:\n```\ngit clone https://github.com/udos86/ng-dynamic-forms.git\ncd ng-dynamic-forms\n```\n\n**2. Install the dependencies**:\n```\nnpm i\n```\n\n**3. Build the library**:\n```\nnpm run build:lib\n```\n\n**4. Run the application**:\n```\nng serve\n```\n\n\n## Basic Usage\n\n**1. Import the UI module**:\n```typescript\nimport { DynamicFormsMaterialUIModule } from \"@ng-dynamic-forms/ui-material\";\n\n@NgModule({\n    imports: [\n        ReactiveFormsModule,\n        DynamicFormsMaterialUIModule\n    ]\n})\n\nexport class AppModule {}\n```\n\n**2. Define your form model**:\n```typescript\nimport {\n    DynamicFormModel,\n    DynamicCheckboxModel,\n    DynamicInputModel,\n    DynamicRadioGroupModel\n} from \"@ng-dynamic-forms/core\";\n\nexport const MY_FORM_MODEL: DynamicFormModel = [\n\n    new DynamicInputModel({\n        id: \"sampleInput\",\n        label: \"Sample Input\",\n        maxLength: 42,\n        placeholder: \"Sample input\"\n    }),\n\n    new DynamicRadioGroupModel\u003cstring\u003e({\n        id: \"sampleRadioGroup\",\n        label: \"Sample Radio Group\",\n        options: [\n            {label: \"Option 1\", value: \"option-1\"},\n            {label: \"Option 2\", value: \"option-2\"},\n            {label: \"Option 3\", value: \"option-3\"}\n        ],\n        value: \"option-3\"\n    }),\n\n    new DynamicCheckboxModel({\n        id: \"sampleCheckbox\",\n        label: \"I do agree\"\n    })\n];\n```\n\n**3. Create a** `FormGroup` **via** `DynamicFormService`:\n```typescript\nimport { MY_FORM_MODEL } from \"./my-dynamic-form.model\";\nimport { DynamicFormModel, DynamicFormService } from \"@ng-dynamic-forms/core\";\n\nexport class MyDynamicFormComponent {\n    formModel: DynamicFormModel = MY_FORM_MODEL;\n    formGroup = this.formService.createFormGroup(this.formModel);\n\n    constructor(private formService: DynamicFormService) {}\n}\n```\n\n**4. Add a** `DynamicFormComponent` **to your template and bind its** `[group]` **and** `[model]` **property**:\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n\n    \u003cdynamic-material-form [group]=\"formGroup\" [model]=\"formModel\"\u003e\u003c/dynamic-material-form\u003e\n                            \n\u003c/form\u003e\n```\n\n\n## UI Modules\n\nNG Dynamic Forms is built to provide **solid yet unobtrusive** support for a variety of common UI libraries:\n\n* **[Basic](https://github.com/udos86/ng-dynamic-forms/tree/master/projects/ng-dynamic-forms/ui-basic)**\n* **[Foundation](https://github.com/udos86/ng-dynamic-forms/tree/master/projects/ng-dynamic-forms/ui-foundation)**\n* **[Ionic](https://github.com/udos86/ng-dynamic-forms/tree/master/projects/ng-dynamic-forms/ui-ionic)**\n* **[Material](https://github.com/udos86/ng-dynamic-forms/tree/master/projects/ng-dynamic-forms/ui-material)**\n* **[NG Bootstrap](https://github.com/udos86/ng-dynamic-forms/tree/master/projects/ng-dynamic-forms/ui-ng-bootstrap)**\n* **[ngx-bootstrap](https://github.com/udos86/ng-dynamic-forms/tree/master/projects/ng-dynamic-forms/ui-ngx-bootstrap)**\n* **[PrimeNG](https://github.com/udos86/ng-dynamic-forms/tree/master/projects/ng-dynamic-forms/ui-primeng)**\n\nYou can instantly plug in your favorite form controls by **installing the appropriate\npackage and its peer dependencies**:\n```\nnpm i @ng-dynamic-forms/ui-\u003clibrary-name\u003e -S\n```\n\n**Now just import the UI module**:\n```typescript\n@NgModule({\n    imports: [\n        ReactiveFormsModule,\n        DynamicFormsMaterialUIModule\n    ]\n})\n\nexport class AppModule {}\n```\n\nFor creating the form markup all UI modules come with a `DynamicFormComponent` that **can easily be added** to\nyour component template:\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n\n    \u003cdynamic-material-form [group]=\"formGroup\" [model]=\"formModel\"\u003e\u003c/dynamic-material-form\u003e\n                               \n\u003c/form\u003e\n```\n\nAlternatively you can **directly make use of a specific** `DynamicFormControlComponent` to gain more control over rendering:\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n\n    \u003cdynamic-material-form-control *ngFor=\"let controlModel of formModel\"\n                                   [group]=\"formGroup\"\n                                   [model]=\"controlModel\"\u003e\u003c/dynamic-material-form-control\u003e\n\u003c/form\u003e\n```\n\nDue to technical restrictions or external dependencies still being in development the support of major form controls \nvaries among UI packages. **See the following compatibility table**:\n\n|                \t| ui-basic \t| ui-ngx-bootstrap \t| ui-foundation \t| ui-ionic \t| ui-material \t| ui-ng-bootstrap \t| ui-primeng \t|\n|----------------\t|:--------:\t|:----------------:\t|:-------------:\t|:--------:\t|:-----------:\t|:---------------:\t|:----------:\t|\n| Checkbox       \t|     ✓    \t|         ✓        \t|       ✓       \t|     ✓    \t|      ✓      \t|        ✓        \t|      ✓     \t|\n| Checkbox Group \t|     ✓    \t|         ✓        \t|       ✓       \t|     ✓    \t|      ✓      \t|        ✓        \t|      ✓     \t|\n| Colorpicker    \t|   ****   \t|         ✗        \t|      ****     \t|   ****   \t|     ****    \t|       ****      \t|      ✓     \t|\n| Datepicker     \t|     *    \t|         ✓        \t|       *       \t|     ✓    \t|      *      \t|        ✓        \t|      ✓     \t|\n| Editor         \t|     ✗    \t|         ✗        \t|       ✗       \t|     ✗    \t|      ✗      \t|        ✗        \t|      ✓     \t|\n| File Upload    \t|    **    \t|        **        \t|       **      \t|     ✗    \t|      **     \t|        **       \t|     **     \t|\n| Input          \t|     ✓    \t|         ✓        \t|       ✓       \t|     ✓    \t|      ✓      \t|        ✓        \t|      ✓     \t|\n| Radio Group    \t|     ✓    \t|         ✓        \t|       ✓       \t|     ✓    \t|      ✓      \t|        ✓        \t|      ✓     \t|\n| Rating         \t|     ✗    \t|         ✓        \t|       ✗       \t|     ✗    \t|      ✗      \t|        ✗        \t|      ✓     \t|\n| Select         \t|     ✓    \t|         ✓        \t|       ✓       \t|     ✓    \t|      ✓      \t|        ✓        \t|      ✓     \t|\n| Slider         \t|    ***   \t|        ***       \t|      ***      \t|     ✓    \t|      ✓      \t|       ***       \t|      ✓     \t|\n| Switch         \t|     ✗    \t|         ✗        \t|       ✓       \t|     ✓    \t|      ✓      \t|        ✗        \t|      ✓     \t|\n| Textarea       \t|     ✓    \t|         ✓        \t|       ✓       \t|     ✓    \t|      ✓      \t|        ✓        \t|      ✓     \t|\n| Timepicker     \t|     *    \t|         ✓        \t|       *       \t|     ✓    \t|      *      \t|        ✓        \t|      ✓     \t|\n\n**\\*)** datetime controls can be achieved using a `DynamicInputModel` with `inputType: \"date\"` or `inputType: \"time\"`\n\n**\\*\\*)** file upload controls can be achieved using a `DynamicInputModel` with `inputType: \"file\"`\n\n**\\*\\*\\*)** slider controls can be achieved using a `DynamicInputModel` with `inputType: \"range\"`\n\n**\\*\\*\\*\\*)** color picker controls can be achieved using a `DynamicInputModel` with `inputType: \"color\"`\n\n\n## Form Groups\n\nIn order to improve clarity it's often considered good practice to group forms into several logical `fieldset` sections.\n\nThus NG Dynamic Forms supports nesting of form groups out of the box!\n \n**1. Declare a** `DynamicFormGroupModel` within your form model and **add it's models to the** `group` **array**:\n ```typescript\nexport const MY_FORM_MODEL: DynamicFormModel = [\n \n    new DynamicFormGroupModel({\n        id: \"fullName\",\n        legend: \"Name\",\n        group: [\n            new DynamicInputModel({\n                id: \"firstName\",\n                label: \"First Name\"\n            }),\n            new DynamicInputModel({\n                id: \"lastName\",\n                label: \"Last Name\"\n            })\n        ]\n    }),\n    \n    new DynamicFormGroupModel({\n        id: \"address\",\n        legend: \"Address\",\n        group: [\n            new DynamicInputModel({\n                id: \"street\",\n                label: \"street\"\n            }),\n            new DynamicInputModel({\n                id: \"zipCode\",\n                label: \"Zip Code\"\n            })\n        ]\n    })\n];  \n ```\n \n**2. Create a** `FormGroup` **and add a** `DynamicFormComponent`:\n```typescript\nformGroup = this.formService.createFormGroup(this.formModel);\n```\n\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n\n    \u003cdynamic-material-form [group]=\"formGroup\" [model]=\"formModel\"\u003e\u003c/dynamic-material-form\u003e\n                            \n\u003c/form\u003e\n```\n\n**3. To manipulate an existing** `DynamicFormGroupModel` **you can simply use** `DynamicFormService`:\n\n* `addFormGroupControl(...)`\n* `insertFormGroupControl(...)`\n* `moveFormGroupControl(...)`\n* `removeFormGroupControl(...)`\n\n\n## Form Arrays\n\nSometimes forms need to allow the user to dynamically add multiple items of the same kind to it, e.g. addresses, products and so on.\n\nParticularly for this reason Angular provides so called [**Form Arrays**](https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2).\n\nFortunately, NG Dynamic Forms is capable of managing such nested form structures!  \n\n**1. Add a** `DynamicFormArrayModel` **to your form model**: \n```typescript\nexport const MY_FORM_MODEL: DynamicFormModel = [\n\n    new DynamicFormArrayModel({\n        id: \"myFormArray\"\n    })\n];\n```\n\n**2. Add the** `groupFactory` **property** to the `DynamicFormArrayModel` **and assign a function** to it which **returns\nthe structure** of a single form array item:\n```typescript\nnew DynamicFormArrayModel({\n    id: \"myFormArray\",\n    initialCount: 5,\n    groupFactory: () =\u003e {\n        return [\n            new DynamicInputModel({\n                id: \"myInput\",\n                label: \"My Input\"\n            })\n        ];\n    }\n})\n```\n\n**3. Create a** `FormGroup` **via** `DynamicFormService` **and bind it to your component template**:\n```typescript\nthis.formGroup = this.formService.createFormGroup(this.formModel);\n```\n\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n\n    \u003cdynamic-material-form [group]=\"formGroup\" [model]=\"formModel\"\u003e\u003c/dynamic-material-form\u003e\n\n    \u003cbutton type=\"button\" (click)=\"addItem()\"\u003eAdd item\u003c/button\u003e\n    \u003cbutton type=\"button\" (click)=\"clear()\"\u003eRemove all items\u003c/button\u003e\n\n\u003c/form\u003e\n```\n\n**4. You can now easily modify your form array with** `DynamicFormService`:\n```typescript\nngOnInit() {\n    this.formArrayModel = this.formService.findModelById\u003cDynamicFormArrayModel\u003e(\"myFormArray\", this.formModel);\n    this.formArrayControl = this.formService.findControlByModel\u003cFormArray\u003e(this.formArrayModel, this.formGroup); \n}\n\naddItem() {\n    this.formService.addFormArrayGroup(this.formArrayControl, this.formArrayModel);\n    this.formService.detectChanges();\n}\n\nclear() {\n    this.formService.clearFormArray(this.formArrayControl, this.formArrayModel);\n    this.formService.detectChanges();\n}\n```\n\nNever forget to trigger change detection via `detectChanges` when updating a form at runtime!\n\nAlright, works like a charm! \n\nBut what if we want to append an additional remove `\u003cbutton\u003e` for each array group?\n\nParticularly for this case you can add a `\u003cng-template\u003e` and **declare some custom content** that is **rendered equally for all form array groups**:\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n\n    \u003cdynamic-material-form [group]=\"formGroup\" [model]=\"formModel\"\u003e\n    \n        \u003cng-template modelId=\"myFormArray\"\u003e\n\n            \u003cbutton type=\"button\" (click)=\"onClick()\"\u003eLabel\u003c/button\u003e\n\n        \u003c/ng-template\u003e\n                                \n    \u003c/dynamic-material-form\u003e\n\n\u003c/form\u003e       \n```\n\nWhenever a `\u003cng-template\u003e` is applied to a `DynamicFormArrayModel`, `NgTemplateOutletContext` **is internally bound to \nthe associated** `DynamicFormArrayGroupModel`. \n\nThat means **you can access the group object and it's properties by either declaring a local default template variable** or individual local template variables.\n\n\u003e see chapter on [Custom Templates](#custom-templates)\n\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n\n    \u003cdynamic-material-form [group]=\"formGroup\" [model]=\"formModel\"\u003e\n    \n        \u003cng-template modelId=\"myFormArray\" let-group let-index=\"index\" let-context=\"context\"\u003e\n\n            \u003cbutton type=\"button\" (click)=\"removeItem(context, index)\"\u003eRemove Item\u003c/button\u003e\n            \u003cbutton type=\"button\" (click)=\"insertItem(group.context, group.index + 1)\"\u003eAdd Item\u003c/button\u003e\n\n        \u003c/ng-template\u003e\n                                \n    \u003c/dynamic-material-form\u003e\n\n\u003c/form\u003e       \n```\n\nThis is extremely useful when you'd like to implement a remove or insert function:\n```typescript\nremoveItem(context: DynamicFormArrayModel, index: number) {\n    this.formService.removeFormArrayGroup(index, this.formArrayControl, context);\n    this.formService.detectChanges();\n}\n\ninsertItem(context: DynamicFormArrayModel, index: number) {\n    this.formService.insertFormArrayGroup(index, this.formArrayControl, context);\n    this.formService.detectChanges();\n}\n```\n\nUsing `DynamicFormService` again, **you can even change the order of the groups** in a form array dynamically:\n```typescript\nthis.formService.moveFormArrayGroup(index, -1, this.formArrayControl, context);\nthis.formService.detectChanges();\n```\n\n\n## Form Layouts\n\nWhen using a NG Dynamic Forms UI package, e.g. `ui-bootstrap`, **all essential** form classes of the underlying CSS library\n(like `form-group` or `form-control`) are automatically put in place for you in the template of the corresponding `DynamicFormControlComponent`.\n\nApart from that, NG Dynamic Forms does not make any further presumptions about optional CSS classes and leaves advanced layouting all up to you. That's **solid** yet **unobtrusive**.\n\nSo let's say we want to implement a beautifully aligned Bootstrap [horizonal form](http://getbootstrap.com/css/#forms-horizontal)...\n\nAt first we have to append the mandatory Bootstrap CSS class `form-horizontal` to the `\u003cform\u003e` element in our template:\n```html\n\u003cform class=\"form-horizontal\" [formGroup]=\"formGroup\"\u003e\n\n    \u003cdynamic-bootstrap-form [group]=\"formGroup\" [model]=\"formModel\"\u003e\u003c/dynamic-bootstrap-form\u003e\n   \n\u003c/form\u003e\n```\n\nNow we need to position the `\u003clabel\u003e` and the `form-control` using the Bootstrap [grid system](http://getbootstrap.com/css/#grid). \n\nBut since all the template logic for the form controls is capsuled in the component scope we cannot directly attach those necessary CSS classes to markup. \n\nDon't worry!\n\nArbitrary CSS classes can be provided for any form control by binding a `DynamicFormLayout` to a `DynamicFormControlComponent`. \n\nA `DynamicFormLayout` is a simple object literal that associates a CSS class configuration object with a model id.\n\nBy differentiating between `element` and `grid `context NG Dynamic Forms can automatically apply the \nCSS class strings in the component template based on [position identifiers](https://github.com/udos86/ng-dynamic-forms/blob/master/projects/ng-dynamic-forms/core/src/lib/model/misc/dynamic-form-control-layout.model.ts):\n```typescript\nexport const MY_FORM_LAYOUT = {\n    \n    \"myFormControlModelId\": {\n        element: {\n            label: \"control-label\"\n        },\n        grid: {\n            control: \"col-sm-9\",\n            label: \"col-sm-3\"\n        }\n    },\n    \n    \"myOtherFormControlModelId\": {\n        element: {\n            label: \"control-label\"\n        },\n        grid: {\n            control: \"col-sm-9\",\n            label: \"col-sm-3\"\n        }\n    }\n};\n```\n\nTo reference this `DynamicFormLayout` we now just create another component class member:\n```typescript\nimport { MY_FORM_LAYOUT } from \"./my-dynamic-form.layout\";\n\nexport class MyDynamicFormComponent implements OnInit {\n    formModel: DynamicFormModel = MY_FORM_MODEL;\n    formLayout: DynamicFormLayout = MY_FORM_LAYOUT;\n    formGroup = this.formService.createFormGroup(this.formModel);\n\n    constructor(private formService: DynamicFormService) {}\n}\n```\n\nFinally we pass the form layout to our `DynamicFormComponent` via input binding:\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n\n    \u003cdynamic-bootstrap-form [group]=\"formGroup\"\n                            [layout]=\"formLayout\"\n                            [model]=\"formModel\"\u003e\u003c/dynamic-bootstrap-form\u003e\n                               \n\u003c/form\u003e\n```\n\nUsing this approach we are able to strictly decouple layout information from pure form models.\n\n\n## Form Control Configuration\n\nNo matter which UI library you're using, usually there is a set of basic properties that apply universally to a certain type of form control. \n\nSo, when picking e.g. a slider component, you'll always find an `@Input()` to control its minimum / maximum value and its orientation.\n\nWhenever that's the case NG Dynamic Forms directly provides an abstract configuration property on the corresponding `DynamicFormControlModel`:\n```typescript\nnew DynamicSliderModel({\n    id: \"mySlider\",\n    min: 0,\n    max: 10,\n    vertical: true\n})\n```\n\nFurthermore, very often there are additional component features that are totally library-specific.  \n\nSo, when using e.g. Material there is a unique `@Input()` for inverting a slider component.\n\nNG Dynamic Forms gives you the freedom to utilize such an individual parameter, as well.  \n\nAll you need to do is to put it in the `additional` configuration object of your `DynamicFormValueControlModel`: \n```typescript\nnew DynamicSliderModel({\n    id: \"mySlider\",\n    min: 0,\n    max: 10,\n    vertical: true\n    additional: {\n        invert: true\n    }\n})\n```\n\n\n## Form Control Events\n\nWhen developing forms it's often useful to keep track of certain events that occur on a specific form control. \n\nWith NG Dynamic Forms you can directly listen to the three most common events, \n`blur`, `change` and `focus`, both on `DynamicFormControlComponent` and `DynamicFormComponent`:\n```html\n\u003cdynamic-material-form [group]=\"formGroup\"\n                       [model]=\"formModel\"\n                       (blur)=\"onBlur($event)\"\n                       (change)=\"onChange($event)\"\n                       (focus)=\"onFocus($event)\"\u003e\u003c/dynamic-material-form\u003e\n```\n```html\n\u003cform [formGroup]=\"myFormGroup\"\u003e\n\n    \u003cdynamic-material-form-control *ngFor=\"let controlModel of myFormModel\"\n                                   [group]=\"myFormGroup\"\n                                   [model]=\"controlModel\"\n                                   (blur)=\"onBlur($event)\"\n                                   (change)=\"onChange($event)\"\n                                   (focus)=\"onFocus($event)\"\u003e\u003c/dynamic-material-form-control\u003e\n\u003c/form\u003e\n```\n\nThe object passed to your handler function gives you any control and model information needed for further processing.\n\nThe `$event` property even grants access to the original event:\n```typescript\ninterface DynamicFormControlEvent {\n    $event: Event | FocusEvent | DynamicFormControlEvent | any;\n    context: DynamicFormArrayGroupModel | null;\n    control: FormControl;\n    group: FormGroup;\n    model: DynamicFormControlModel;\n    type: string;\n}\n```\n  \nBut when using a UI library usually there are a bunch of additional events provided for certain form control components.\n\nOf course, NG Dynamic Forms won't let you down here.\n\nAll custom UI events are pooled by an individual `@Output()` utilizing the respective library prefix.    \n```html\n\u003cdynamic-material-form [group]=\"formGroup\"\n                       [model]=\"formModel\"\n                       (matEvent)=\"onMatEvent($event)\"\u003e\u003c/dynamic-material-form\u003e\n```\n\n\n## Updating Form Controls\n\nNG Dynamic Forms entirely relies on the Angular `ReactiveFormsModule`. \nTherefore the `value` property of a `DynamicFormValueControlModel` **cannot be two-way-bound** via `[(ngModel)]`. \nAlso, dating back to RC.6, Angular [**does not allow**](https://github.com/angular/angular/issues/11271) property bindings of the `disabled` attribute in reactive forms. \n\nYet updating either the value or status of a form control at runtime can easily be achieved.\nAt first we need to get a reference to its `DynamicFormControlModel` representation:\n\n```typescript\nconst inputModel = this.formService.findModelById\u003cDynamicInputModel\u003e(\"myInput\", this.formModel);\n```\n\nAfter that we just bring the convenient `value` and `disabled` setters of `DynamicFormValueControlModel` into play and we're fine:\n\n```typescript\ninputModel.value = \"New Value\";\ninputModel.disabled = true;\n```\n\nThe modifications immediately are reflected in the user interface. So far so good.\n\nBut what about other data? Since a `DynamicFormControlModel` is bound directly to a `DOM` element via Angular core mechanisms, \nchanging one of its properties should automatically trigger an update of the user interface as well, right?\n\nNow **BEWARE**!\n\nDue to performance reasons NG Dynamic Forms makes use of `ChangeDetectionStrategy.OnPush` under the hood. \nTherefore changing any property on a `DynamicFormControl` except for `value` and `disabled` will not cause an automatic DOM update to occur.\n\nInstead you always have to call `detectChanges()` on `DynamicFormService` after updating the model to signal that the library should manually trigger a change detection.\n```typescript\ninputModel.label = \"New Label\";\n\nthis.formService.detectChanges();\n```\n\nTo optimize this you can optionally pass a `DynamicFormComponent` to `detectChanges()` to narrow the number of elements that are affected by the forthcoming change detection:\n```typescript\n@ViewChild(DynamicMaterialFormComponent, {static: true}) formComponent°!: DynamicMaterialFormComponent;\n\n//...\nthis.formService.detectChanges(this.formComponent);\n```\n\n\n## Custom Templates\n\nAs already mentioned, NG Dynamic Forms gives you a lot of freedom in adjusting your form layout via CSS classes. \n\nHowever there are situations where you would like to add custom markup for some of your form controls, as well. \n\nIn order to do so, just **put a** `\u003cng-template\u003e` **inside your dynamic form control element** and **set a** `modelId` **property** to assign it to a certain control.\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n    \n    \u003cdynamic-material-form [group]=\"formGroup\" [model]=\"formModel\"\u003e\n                                    \n        \u003cng-template modelId=\"myInput\"\u003e\n        \n            \u003cp\u003eSome custom markup\u003c/p\u003e\n            \n        \u003c/ng-template\u003e\n        \n    \u003c/dynamic-material-form\u003e\n    \n\u003c/form\u003e\n```\n\nAlternatively **you can also apply** `modelType` **instead of** `modelId` **to reuse a template** for several form controls of the same type:\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n    \n    \u003cdynamic-material-form [group]=\"formGroup\" [model]=\"formModel\"\u003e\n                                    \n        \u003cng-template modelType=\"ARRAY\"\u003e\n        \n            \u003cp\u003eJust some custom markup\u003c/p\u003e\n            \n        \u003c/ng-template\u003e\n\n    \u003c/dynamic-material-form\u003e\n    \n\u003c/form\u003e\n```\n\n**And it's getting better!** \n\nSince for every template `NgTemplateOutletContext` is internally bound to the corresponding `DynamicFormControlModel` **you \ncan use local template variables to reference your models' properties**:\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n\n    \u003cdynamic-material-form [group]=\"formGroup\" [model]=\"formModel\"\u003e\n                                    \n        \u003cng-template modelId=\"myInput\" let-id=\"id\"\u003e\n        \n            \u003cp\u003eSome custom markup for {{ id }}\u003c/p\u003e\n            \n        \u003c/ng-template\u003e                                               \n    \n    \u003c/dynamic-material-form\u003e\n    \n\u003c/form\u003e\n```\n\nFinally **you can determine whether the template is rendered before or after the actual form control** by using the `align` property:\n```html\n\u003cform [formGroup]=\"formGroup\"\u003e\n    \n    \u003cdynamic-material-form [group]=\"formGroup\" [model]=\"formModel\"\u003e\n                            \n        \u003cng-template modelId=\"myInput\" align=\"START\"\u003e\n        \n            \u003cp\u003eSome custom markup\u003c/p\u003e\n            \n        \u003c/ng-template\u003e\n        \n    \u003c/dynamic-material-form\u003e\n    \n\u003c/form\u003e\n```\n\n\n## Custom Validators\n\nAdding built-in Angular validators to any `DynamicFormControlModel` is plain and simple! \n\nJust reference a function from `Validators` class by it's name in the `validators` or `asyncValidators` configuration object:\n```typescript \nnew DynamicInputModel({\n    id: \"myInput\",\n    label: \"My Input\",\n    validators: {\n        required: null,\n        minLength: 3\n    }\n})\n```\n\nSo far so good! \n\nBut what if you'd like to introduce some custom validator as well?\n```typescript\nexport function myCustomValidator(control: AbstractControl): ValidationErrors | null {\n    const hasError = control.value ? (control.value as string).startsWith(\"abc\") : false;\n    return hasError ? {myCustomValidator: true} : null;\n}\n```\n\nJust **provide your validator functions via default** `NG_VALIDATORS` **or** `NG_ASYNC_VALIDATORS` **token**:\n```typescript\n@NgModule({\n    // ...\n    providers: [\n        {provide: NG_VALIDATORS, useValue: myCustomValidator, multi: true}\n    ]\n})\n``` \n\n\u003e **Note:** thoughtram.io - [Custom Validators in Angular 2](http://blog.thoughtram.io/angular/2016/03/14/custom-validators-in-angular-2.html)\n\n**You're now ready to apply your custom validator to your model**:\n```typescript \nnew DynamicInputModel({\n    id: \"myInput\",\n    label: \"My Input\",\n    validators: {\n        myCustomValidator: null\n    }\n})\n```\n\n**But beware! There's a catch!**\n\nInternally NG Dynamic Forms resolves a provided validator by it's function name.\n\nThough **when uglifying code** for production this **information is irretrievably lost**.\n\nTo save you from this issue NG Dynamic Forms comes up with **a special** `InjectionToken\u003cMap\u003cstring, Validator | ValidatorFactory\u003e\u003e` **named** `DYNAMIC_VALIDATORS` to which **you should additionally provide** any custom validator function:\n```typescript \nproviders: [\n    {\n        provide: NG_VALIDATORS,\n        useValue: myCustomValidator,\n        multi: true\n    },\n    {\n        provide: DYNAMIC_VALIDATORS,\n        useValue: new Map\u003cstring, Validator | ValidatorFactory\u003e([\n            [\"myCustomValidator\", myCustomValidator]\n        ])\n    }\n]\n```\nYou can also have multiple validators on the same input bu providing multiple key|value pairs in the useValue:\n```typescript \nproviders: [\n    {\n        provide: NG_VALIDATORS,\n        useValue: myCustomValidator,\n        multi: true\n    },\n     {\n        provide: NG_VALIDATORS,\n        useValue: myOtherCustomValidator,\n        multi: true\n    },\n    {\n        provide: DYNAMIC_VALIDATORS,\n        useValue: new Map\u003cstring, Validator | ValidatorFactory\u003e([\n            [\"myCustomValidator\", myCustomValidator],\n            [\"myOtherCustomValidator\", myOtherCustomValidator]\n        ])\n    }\n]\n```\n\nAnother suitable solution for most situations would be to **make use of the alternate validator notation**:\n```typescript \nnew DynamicInputModel({\n    id: \"myInput\",\n    label: \"My Input\",\n    validators: {\n        myCustomValidator: {\n            name: myCustomValidator.name,\n            args: null\n        }\n    }\n})\n```\n\n\n## Custom Form Controls\n\nStarting with version 6 NG Dynamic Forms allows you to easily plugin in your own custom form controls.\n\nBeforehand follow [**the standard procedure**](https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html) to build your custom Angular form control:\n```typescript\nimport { Component, forwardRef } from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from \"@angular/forms\";\n\n@Component({\n  selector: 'my-custom-form-control',\n  templateUrl: './my-custom-form-control.component.html',\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() =\u003e MyCustomFormControlComponent),\n      multi: true\n    }\n  ]\n})\nexport class MyCustomFormControlComponent implements ControlValueAccessor {\n\n    //...\n}\n```\n\nNow **create a new** `DynamicFormControlComponent`:\n```typescript\nimport { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewChild } from \"@angular/core\";\nimport { FormGroup } from \"@angular/forms\";\nimport {\n    DynamicFormControlComponent,\n    DynamicFormControlCustomEvent,\n    DynamicFormLayout,\n    DynamicFormLayoutService,\n    DynamicFormValidationService,\n} from \"@ng-dynamic-forms/core\";\nimport { MyCustomFormControlComponent } from \"...\";\n\n@Component({\n    selector: \"my-dynamic-custom-form-control\",\n    templateUrl: \"./my-dynamic-custom-form-control.component.html\",\n    changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class MyDynamicCustomFormControlComponent extends DynamicFormControlComponent {\n    @Input() group!: FormGroup;\n    @Input() layout?: DynamicFormLayout;\n    @Input() model!: /* corresponding DynamicFormControlModel */;\n\n    @Output() blur: EventEmitter\u003cany\u003e = new EventEmitter();\n    @Output() change: EventEmitter\u003cany\u003e = new EventEmitter();\n    @Output() customEvent: EventEmitter\u003cDynamicFormControlCustomEvent\u003e = new EventEmitter();\n    @Output() focus: EventEmitter\u003cany\u003e = new EventEmitter();\n\n    @ViewChild(MyCustomFormControlComponent) myCustomFormControlComponent!: MyCustomFormControlComponent;\n\n    constructor(protected layoutService: DynamicFormLayoutService,\n                protected validationService: DynamicFormValidationService) {\n        super(layoutService, validationService);\n    }\n}\n```\n\nNext **embed your custom form control** into the component template:\n```html\n\u003cng-container [formGroup]=\"group\"\u003e\n\n    \u003cmy-custom-form-control [formControlName]=\"model.id\"\n                            [name]=\"model.name\"\n                            [ngClass]=\"[getClass('element', 'control'), getClass('grid', 'control')]\"\n                            (blur)=\"onBlur($event)\"\n                            (change)=\"onChange($event)\"\n                            (focus)=\"onFocus($event)\"\u003e\u003c/my-custom-form-control\u003e\n\n\u003c/ng-container\u003e\n```\n\nThen **add your newly implemented** `DynamicFormControl` **to** `entryComponents` in your app module:\n```typescript\nentryComponents: [MyDynamicCustomFormControlComponent]\n```\n\nFinally **provide** `DYNAMIC_FORM_CONTROL_MAP_FN` **to overwrite the default mapping** of a concrete `DynamicFormControlModel` to its corresponding `DynamicFormControlComponent`;\n```typescript\nproviders: [\n  {\n    provide: DYNAMIC_FORM_CONTROL_MAP_FN,\n    useValue: (model: DynamicFormControlModel): Type\u003cDynamicFormControl\u003e | null  =\u003e {\n      switch (model.type) {\n        case /* corresponding DynamicFormControlModel */:\n          return MyDynamicCustomFormControlComponent;\n\n        }\n     }\n  }\n]\n```\n\n\n## Validation Messaging\n\nDelivering meaningful validation information to the user is an essential part of good form design. \n\nYet HTML5 already comes up with some [native functionality](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms/Data_form_validation)\nyou very likely want to use [Angular mechanisms](http://blog.thoughtram.io/angular/2016/03/14/custom-validators-in-angular-2.html) \nto gain much more control over validation logic and it's corresponding message output.\n\nAvoiding a library too opinionated in the beginning, NG Dynamic Forms has originally been developed without any kind of obtrusive validation message system in mind.\n\nHowever, due to its very common use case, model-based error messaging has eventually become an optional **built-in feature**. \n\n**Just add an** `errorMessages` **object to any** `DynamicFormControlModel` and **assign error message templates based on** `Validators` **names**:\n```typescript \nnew DynamicInputModel({\n        id: \"myInput\",\n        label: \"My Input\",\n        validators: {\n            required: null\n        },\n        errorMessages: {\n            required: \"{{ label }} is required.\"\n        }\n})\n```\n**Note:** Error message templates allow the following placeholders: \n\n* `{{ propertyName }}` where `propertyName` is a property of the model, for example `{{ label }}`.\n* `{{ validator.propertyName }}` where `propertyName` is a property of the object returned by validation function, for example `{{ validator.requiredPattern }}` in case of pattern validator.\n\n**Error messaging is automatically enabled whenever** `errorMessages` **are declared on a** `DynamicFormControlModel`. \n\nBy default error messages are shown whenever the corresponding form control is invalid and blurred at the same time and has already been touched.\n\nSince the condition for displaying error messages often is a subject to individual user experience preferences you can customize this by\nproviding a so called `DynamicErrorMessagesMatcher` via the `DYNAMIC_ERROR_MESSAGES_MATCHER` injection token:\n```ts\nexport const MY_CUSTOM_ERROR_MESSAGES_MATCHER =\n    (control: AbstractControl, model: DynamicFormControlModel, hasFocus: boolean) =\u003e {\n        return //...\n    };\n\n// ...\n\nproviders: [\n    {\n        provide: DYNAMIC_ERROR_MESSAGES_MATCHER,\n        useValue: myCustomErrorMessagesMatcher\n    },\n]\n```\n\nBy default the `DEFAULT_ERROR_STATE_MATCHER` is active:\n```ts\nexport const DEFAULT_ERROR_STATE_MATCHER: DynamicErrorMessagesMatcher =\n    (control: AbstractControl, model: DynamicFormControlModel, hasFocus: boolean) =\u003e {\n        return control.touched \u0026\u0026 !hasFocus;\n    };\n```\n\nPlease note here that NG Dynamic Forms always assumes both the control being invalid and error messages being defined on the model \nas a fixed precondition.\n\n## Related Form Controls\n\nIn many forms the state of a certain form control directly depends on the `value` or `status` of some other form control.\n\nImplementing such a connection manually would be time-consuming and only lead to undesired boilerplate code.\n\nNG Dynamic Forms enables you to declaratively add form control relations by using so called `DynamicFormControlMatcher`s.\n\nA matcher defines the action that should take place for a predefined `match` when a `value` or `state` change has occured on the related form control.\n```typescript\nexport interface DynamicFormControlMatcher {\n    match: string;\n    opposingMatch: string | null;\n    onChange(hasMatch: boolean, model: DynamicFormControlModel, control: FormControl, injector: Injector): void;\n}\n```\n\nAt the moment there are the following **default matchers** available:\n\n* `DisabledMatcher`\n* `HiddenMatcher`\n* `RequiredMatcher`\n\n**NOTE: Always make sure that you're providing every** `DynamicFormControlMatcher` **in your** `app.module`:\n```typescript\nproviders: [\n    // ...\n    DISABLED_MATCHER,\n    REQUIRED_MATCHER\n]\n```\n\n That way you're also totally **free to implement your own custom matcher**:\n```typescript\n export const MyCustomMatcher: DynamicFormControlMatcher = {\n    match: MATCH_CUSTOM,\n    opposingMatch: MATCH_CUSTOM_OPPOSITE,\n    onChange(hasMatch: boolean, model: DynamicFormControlModel): void {\n        if (hasMatch) {\n            console.log(\"It's a match\");\n        }\n    }\n};\n```\n```typescript\nexport const MY_CUSTOM_MATCHER: ValueProvider = {\n    provide: DYNAMIC_MATCHERS,\n    useValue: MyCustomMatcher,\n    multi: true\n};\n```\n\nSo let's pretend we need to have our textarea `myTextArea` disabled as soon as the third option of our select menu `mySelect` is chosen.\n\nJust add a `relations` property to your `DynamicFormControlModel`, then declare a `DynamicFormControlRelation` by setting a `match` for a certain `DynamicFormControlCondition`:\n\n```typescript\nnew DynamicTextAreaModel(\n    {\n        id: \"myTextArea\",\n        label: \"My Textarea\",\n        relations: [\n            {\n                match: MATCH_DISABLED,\n                when: [{ id: \"mySelect\", value: \"option-3\" }]\n            }\n        ]\n    }\n```\n**That's it** - the library will automatically add all the pieces together under the hood.\n\n*But what if `myTextArea` should depend on another control `myRadioGroup` as well?*\n\nLuckily there's support for **multi-related form controls**, too.\n\nJust add a second `DynamicFormControlCondition` entry and (optionally) define how all conditions should logically be connected via `operator`:\n```typescript\nnew DynamicTextAreaModel(\n    {\n        id: \"myTextArea\",\n        label: \"My Textarea\",\n        relations: [\n            {\n                match: MATCH_DISABLED,\n                operator: AND_OPERATOR,\n                when: [\n                    { id: \"mySelect\", value: \"option-3\" },\n                    { id: \"myRadioGroup\", value: \"option-4\" }\n                ]\n            }\n        ]\n    }\n)\n```\n\n\n## JSON Export \u0026 Import\n\nSooner or later you likely want to persist your dynamic form model in order to restore it at some point in the future.\n\nThat's why all `DynamicFormControlModel`s have been prepared to **properly export to JSON**: \n```typescript\nstoreForm() {\n    const json = JSON.stringify(this.formModel);\n    \n    // ...store JSON in localStorage or transfer to server\n}\n```\n\nIn order to recreate a form from JSON just make use of the corresponding function provided by `DynamicFormService`:\n```typescript\nrestoreForm() {\n    let json: string;\n    \n    // ...load JSON from localStorage or server\n    \n    this.formModel = this.formService.fromJSON(json);\n}\n```\n\n\n## JSON Form Models\n\nBy default NG Dynamic Forms **embraces prototypical inheritance** and forces you to use constructor functions when modelling a form.\n\nDepending on your general set-up or individual preferences sometimes it's more suitable to provide a form model in plain JSON, though. \n\nFortunately, **this is perfectly fine and supported**, as well. \n\nTo specify a single JSON form control model just **assign the mandatory** `type` **property**: \n```typescript\n[\n    {\n        \"type\": \"INPUT\",\n        \"id\": \"sampleInput\",\n        \"label\": \"Sample Input\",\n        \"maxLength\": 42,\n        \"placeholder\": \"Sample input\"\n    },\n    {\n        \"type\": \"RADIO_GROUP\",\n        \"id\": \"sampleRadioGroup\",\n        \"label\": \"Sample Radio Group\",\n        \"options\": [\n            {\"label\": \"Option 1\", \"value\": \"option-1\"},\n            {\"label\": \"Option 2\", \"value\": \"option-2\"},\n            {\"label\": \"Option 3\", \"value\": \"option-3\"}\n        ],\n        \"value\": \"option-3\"    \n    },\n    {\n        \"type\": \"CHECKBOX\",\n        \"id\": \"sampleCheckbox\",\n        \"label\": \"I do agree\"\n    }\n]\n```\n\nAfter having asynchronously loaded the JSON form model into your application **don't forget to transform it** via `fromJSON()` **before creating** a `FormGroup`. \n```typescript\nngOnInit() {\n    this.http.get\u003cobject[]\u003e('./app/my-dynamic-form.model.json').subscribe(formModelJson =\u003e {\n        this.formModel = this.formService.fromJSON(formModelJson);\n        this.formGroup = this.formService.createFormGroup(this.formModel);\n    });\n}\n```\n\n\n## Text Masks\n\nWhenever an `\u003cinput\u003e` element needs to be filled in a predefined format, text masks can make a nice form enhancement.\n\nSince Angular does not deliver an appropriate feature by default, NG Dynamic Forms integrates  [**ngx-mask**](https://github.com/JsDaddy/ngx-mask).\n\nThat's why some UI packages demand one additional peer dependency to be installed:\n```\nnpm install ngx-mask --save\n```\n\nYou're now capable of adding a `mask` property to any `DynamicInputModel` according to [Text Mask docs](https://github.com/text-mask/text-mask/blob/master/componentDocumentation.md#mask):\n```typescript\nnew DynamicInputModel({\n    id: \"maskedInput\",\n    label: \"Masked Input\",\n    mask: \"00/00/0000\",\n})\n```\n\nFurthermore, you can add additional configuration via `maskConfig` according to the ngx-mask \n ```typescript\nnew DynamicInputModel({\n    id: \"maskedInput\",\n    label: \"Masked Input\",\n    mask: \"00/00/0000\",\n    maskConfig: {\n        showMaskTyped: true\n    },\n})\n```\n\n**Note:** Angular does not support adding multiple custom value accessors to the same input element. Thus, this feature is **not** available to libraries like Material that already do apply a custom value accessor by default.\nIn cases like Prime NG where a component library natively provides some text mask mechanism, NG Dynamic Forms maps the mask configuration to the built-in api.\n\n## Autocompletion\n\nAdding automatic input completion can be key factor to good user experience (especially on mobile devices) and should always \nbe considered when designing forms. \n\nThat's why NG Dynamic Forms keeps you covered here, as well!\n\nFollowing HTML5 [standard behavior](http://www.w3schools.com/tags/att_form_autocomplete.asp), the `autocomplete` attribute is always bound to `on` for any `DynamicFormTextInputControl` form element by default. \nNevertheless you can completely disable this feature by explicitly setting the corresponding model property to `off`:\n```typescript\nimport { AUTOCOMPLETE_OFF } from \"@ng-dynamic-forms/core\";\n\nconst model = new DynamicInputModel({\n    id: \"myInput\",\n    label: \"My Input\",\n    autoComplete: AUTOCOMPLETE_OFF\n});\n```\n\nFurther on NG Dynamic Forms embraces the brand new HTML5 \n[**autofill detail tokens**](https://html.spec.whatwg.org/multipage/forms.html#autofill) by providing \n`AUTOFILL_\u003cTOKEN_NAME|FIELD_NAME\u003e` string constants and `AutoFillUtils` to help you putting together a valid expression:\n\n\u003e **Note:** Jason Grigsby - [Autofill: What web devs should know, but don’t](https://cloudfour.com/thinks/autofill-what-web-devs-should-know-but-dont/)\n\n```typescript\nimport {\n    AutoFillUtils,\n    AUTOFILL_TOKEN_BILLING, \n    AUTOFILL_FIELD_NAME, \n    AUTOCOMPLETE_ON\n} from \"@ng-dynamic-forms/core\";\n\nexport class MySample {\n\n    constructor() {\n        const expression = `${AUTOFILL_TOKEN_BILLING} ${AUTOFILL_FIELD_NAME}`;\n        const model = new DynamicInputModel({\n            id: \"myInput\",\n            label: \"My Input\",\n            autoComplete: AutoFillUtils.validate(expression) ? expression : AUTOCOMPLETE_ON\n        });\n    }\n}\n```\n\nBesides you can make user input more comfortable, providing HTML5 [**datalists**](http://www.w3schools.com/tags/tag_datalist.asp)\nby setting the `list` property of `DynamicInputControlModel`: \n```typescript\nnew DynamicInputModel({\n    id: \"myInput\",\n    label: \"My Input\",\n    list: [\"Alabama\", \"Alaska\", \"Arizona\", \"Arkansas\"]\n})\n```\n\n\n## FAQ\n\n\u003e **Why should I use NG Dynamic Forms?**\n\nYour Angular forms will become highly maintainable as you don't have to care about keeping template markup and program code in sync ever again.\n\n\u003e **When should I use NG Dynamic Forms?**\n\nWhenever your Angular application is driven by multiple complex forms. \n\n\u003e **When should I not use NG Dynamic Forms?**\n\nWhenever your Angular application has to display very simple forms only or extremely individual form UI.  \n\n\u003e **Are there any downsides to using NG Dynamic Forms?**\n\nCertain limitations exist regarding extremely individual form layouts.\n\n\u003e **Does NG Dynamic Forms support custom form controls?**\n\nYes, [it does](#custom-form-controls).\n\n\u003e **Are there any other dynamic forms libraries for Angular?**\n\nYes, namely [ng-formly](https://github.com/formly-js/ng-formly), [ngx-forms](https://github.com/ngx-plus/ngx-forms) and [angular-formio](https://github.com/formio/angular-formio).\n\n\u003e **How can I support this project besides contributing issues or code?**\n\n[Star](https://github.com/udos86/ng-dynamic-forms/stargazers) the repository.\n\n\n## Appendix\n\n* Logo design made by [**oscarana**](http://www.oscarana-art.com)\n","funding_links":[],"categories":["前端相关","Table of contents"],"sub_categories":["Third Party Components"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fudos86%2Fng-dynamic-forms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fudos86%2Fng-dynamic-forms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fudos86%2Fng-dynamic-forms/lists"}