{"id":15282623,"url":"https://github.com/gms1/angular-dynaform","last_synced_at":"2025-10-07T00:31:10.090Z","repository":{"id":57097708,"uuid":"106982308","full_name":"gms1/angular-dynaform","owner":"gms1","description":"angular library for rapid development of model-driven reactive forms","archived":true,"fork":false,"pushed_at":"2020-07-30T00:59:06.000Z","size":9848,"stargazers_count":9,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-07T21:09:42.442Z","etag":null,"topics":["angular","dynamic","dynamic-form","generic","generic-form","json","json-serializable","material","model-driven","reactive","reactive-form"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gms1.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}},"created_at":"2017-10-15T04:01:37.000Z","updated_at":"2023-11-19T16:29:17.000Z","dependencies_parsed_at":"2022-08-20T16:50:51.580Z","dependency_job_id":null,"html_url":"https://github.com/gms1/angular-dynaform","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gms1%2Fangular-dynaform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gms1%2Fangular-dynaform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gms1%2Fangular-dynaform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gms1%2Fangular-dynaform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gms1","download_url":"https://codeload.github.com/gms1/angular-dynaform/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235569499,"owners_count":19011183,"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","dynamic","dynamic-form","generic","generic-form","json","json-serializable","material","model-driven","reactive","reactive-form"],"created_at":"2024-09-30T14:31:48.507Z","updated_at":"2025-10-07T00:31:04.516Z","avatar_url":"https://github.com/gms1.png","language":"TypeScript","readme":"# angular-dynaform\n\n[![npm (scoped)](https://img.shields.io/npm/v/@angular-dynaform/core.svg?colorB=007ec6)](https://www.npmjs.com/package/%40angular-dynaform%2Fcore)\n[![Build Status](https://api.travis-ci.org/gms1/angular-dynaform.svg?branch=master)](https://travis-ci.org/gms1/angular-dynaform)\n[![Coverage Status](https://coveralls.io/repos/github/gms1/angular-dynaform/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/gms1/angular-dynaform?branch=master)\n[![DeepScan Grade](https://deepscan.io/api/projects/698/branches/1106/badge/grade.svg)](https://deepscan.io/dashboard/#view=project\u0026pid=698\u0026bid=1106)\n[![Dependency Status](https://david-dm.org/gms1/angular-dynaform.svg)](https://david-dm.org/gms1/angular-dynaform)\n[![Known Vulnerabilities](https://snyk.io/test/github/gms1/angular-dynaform/badge.svg)](https://snyk.io/test/github/gms1/angular-dynaform)\n\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)\n\n**angular-dynaform** is a library for rapid development of model-driven reactive forms for mobile and web\n\n## Features\n\n- generic, expressive and extendable form library\n- JSON serializable form configuration\n- shared forms for mobile and web\n- form builder\n- observable form values and form value updates using angulars form model as a tree of FormGroups/FormArrays/FormControls\n- observable focus changes\n- application data model to form data model mapping\n- enable/disable or show/hide fields based on conditions defined on related field values\n- generic internationalization (labels, placeholders, options (select/radiobutton))\n- easily extensible through:\n  - custom components\n  - custom validators\n  - custom actions (triggered by blur/focus/click events) and/or observing value/status changes\n\n## Supported UI-Frameworks\n\n- [Material](https://github.com/angular/material2)\n- [Nativescript Angular](https://github.com/NativeScript/nativescript-angular/)\n\n## Links\n\n- [Example on Stackblitz](https://stackblitz.com/edit/gms1-angular-dynaform-material)\n\n## TODO\n\n[TODO](./TODO.md)\n\n\u003e NOTE: Asking for any help! Your contribution is highly welcome!\n\n## Table of Contents\n\n- [Getting Started](#getting-started)\n- [Basic Usage](#basic-usage)\n- [Customization](#customization)\n- [Control-types](#control-types)\n- [License](#license)\n- [Release Notes](#release-notes)\n- [Contributing](#contributing)\n\n## Getting Started\n\n- install the packages:\n\n```shell\nnpm install @angular-dynaform/core --save\nnpm install @angular-dynaform/material --save\n```\n\n\u003e NOTE: please install required peer dependencies if they are not already installed\n\n```shell\nnpm install @angular/common @angular/core @angular/forms rxjs jsep jsonpointerx\n```\n\n## Basic Usage\n\n- import the form modules in the root NgModule of your application:\n\n```typescript\n@NgModule({\n  ...\n  imports: [DynamicFormModule.forRoot(), DynamicMaterialFormModule, ...],\n  ...\n})\nexport class AppModule {\n}\n```\n\n- in other modules, import only the 'DynamicFormModule' and do not import the UI specific modules (e.g 'DynamicMaterialFormModule'):\n\n```typescript\n@NgModule({\n  ...\n  imports: [DynamicFormModule],\n  ...\n})\nexport class SharedModule {\n}\n```\n\n- implement a form:\n\n```typescript\n@Component({\n  selector: 'app-basic-form',\n  template: `\n    \u003cadf-form [model]=\"formModel\" (adfSubmit)=\"onSubmit($event)\"\u003e\u003c/adf-form\u003e\n  `,\n})\nexport class BasicFormComponent {\n  @ViewChild(DynamicForm) dynaForm!: DynamicForm;\n  formModel: FormModel;\n\n  readonly formConfig: FormConfig = {\n    id: 'basic',\n    updateOn: 'change',\n    options: {\n      group: [\n        {\n          id: 'name',\n          modelType: ModelType.MODEL_VALUE,\n          controlType: ControlType.CONTROL_INPUT,\n          options: { label: 'name', placeholder: 'Enter your name', maxLength: 30, minLength: 4 },\n          validators: ['required', 'minLength', 'maxLength'],\n        },\n        {\n          id: 'submit',\n          modelType: ModelType.MODEL_NULL,\n          controlType: ControlType.CONTROL_BUTTON,\n          options: { label: 'Submit' },\n          action: 'submit',\n        },\n      ],\n    },\n  };\n\n  name?: string;\n\n  constructor(private dynamicFormService: DynamicFormService) {\n    this.formModel = this.dynamicFormService.createFormModel(this.formConfig);\n  }\n\n  onSubmit(event: Event): void {\n    this.name = this.formModel.value.name;\n  }\n}\n```\n\n- create the form config:\n\n  - using the Form Builder:\n\n  inject `FormBuilder` into your component class. You can then call its method 'createForm' to create an instance of 'FormBuilderForm'\n\n```typescript\nconst form = formBuilder.createForm({ id: 'exampleForm', updateOn: 'blur' });\n\n// create divisions:\nconst persondiv = form.group.addSubset({ id: 'person', controlType: ControlType.CONTROL_DIVISION });\nconst buttondiv = form.group.addSubset({\n  id: 'buttondivision',\n  controlType: [ControlType.CONTROL_DIVISION],\n  options: { css: { content: 'button-division-content' } },\n});\n\n// add controls to the persondiv division:\npersondiv.group.addControl({\n  id: 'salutation',\n  controlType: ControlType.CONTROL_RADIOGROUP,\n  options: { valueOptions: [{ value: 'mr', label: 'Mr.' }, { value: 'ms', label: 'Ms.' }] },\n  validators: ['required'],\n});\npersondiv.group.addControl({\n  id: 'title',\n  controlType: ControlType.CONTROL_INPUT,\n  options: { label: 'Title', placeholder: 'Enter your title', maxLength: 30, minLength: 2 },\n  validators: ['minLength', 'maxLength'],\n});\npersondiv.group.addControl({\n  id: 'name',\n  controlType: ControlType.CONTROL_INPUT,\n  options: { label: 'name', placeholder: 'Enter your name', maxLength: 60, minLength: 4 },\n  validators: ['required', 'minLength', 'maxLength'],\n});\n\n// add controls to the button division:\nbuttondiv.group.addButton({\n  id: 'clear',\n  controlType: ControlType.CONTROL_BUTTON,\n  options: { label: 'Clear' },\n  action: 'clear',\n});\nbuttondiv.group.addSeparator({\n  id: 'separatorMainButtons',\n  controlType: ControlType.CONTROL_SEPARATOR,\n  options: { css: { container: 'button-separator' } },\n});\nbuttondiv.group.addButton({\n  id: 'reset',\n  controlType: ControlType.CONTROL_BUTTON,\n  options: { label: 'Reset' },\n  action: 'reset',\n});\nbuttondiv.group.addButton({\n  id: 'submit',\n  controlType: ControlType.CONTROL_BUTTON,\n  options: { label: 'Submit' },\n  action: 'submit',\n});\n\n// create to form configuration:\nconst formConfig: FormConfig = form.toFormConfig();\n```\n\n- JSON configuration:\n\n[Configuration of the plunker example](./projects/material-example/src/app/app.config.ts)\n\n[ControlConfig Interface](./projects/angular-dynaform/core/src/lib/config/control-config.ts)\n\n- observable form value and form value update:\n\n```typescript\n    // subscribe to form value changes:\n    dynaForm.valueChanges.subscribe(...);\n\n    // get form value:\n    value = dynaForm.value;\n\n    // init form value (undefined for empty form):\n    dynaForm.initValue(value);\n\n    // clear form value:\n    dynaForm.clearValue();\n\n    // reset form value to the last value provided to 'initValue':\n    dynaForm.resetValue();\n\n```\n\n- observable control values and control value updates:\n\n```typescript\n    ctrlModel = dynaForm.findComponentById(id).model;\n    ctrlModel = dynaForm.model.findControlByPath(path);\n\n    // subscribe to form value changes:\n    ctrlModel.valueChanges.subscribe(...);\n\n    // get form value:\n    value = ctrlModel.value;\n\n    // patch/set form value:\n    ctrlModel.patchValue(value);\n    ctrlModel.setValue(value);\n```\n\n- observable focus changes and click events:\n\n```typescript\n    ctrlComp = dynaForm.findComponentById(id);\n\n    // subscribe to focus changes:\n    ctrlComp.focusChanges.subscribe((focus) =\u003e { console.log(focus ? 'got focus' : 'lost focus');});\n\n    // subscribe to click event:\n    ctrlComp.click.subscribe(...);\n```\n\n- get/set form data using an application data model to form data model mapping\n\nIn your form configuration define the JSON pointer to the application data model and\nuse 'dynaForm.initValueFromAppModel' instead of 'dynaForm.initValue' and 'dynaForm.valueToAppModel' instead of 'dynaForm.value'\n\n- enable/disable or show/hide fields based on conditions defined on related field values\n\nIn the relations expressions, you can combine all common arithmetic, comparison, and logical operators, as well as references to form control values. 'foo.bar' would reference the value of the 'bar' control in the 'foo' group;\nIn this example, the 'newsletter' checkbox will only be enabled if the 'atc' checkbox has been selected:\n\n```typescript\n          group: [\n            {\n              key: 'atc',\n              controlType: ControlType.CONTROL_CHECKBOX,\n              ...\n            },\n            {\n              key: 'newsletter',\n              controlType: ControlType.CONTROL_CHECKBOX,\n              ...\n              relations: {enable: 'atc'}\n            }\n          ]\n```\n\n- layout/styling\n\nyou can optionally assign additional CSS classes using **ControlConfig.options.css** and let **angular-dynaform** add them to the container, control, label sections of the corresponding component\n\nThe following CSS classes are predefined:\n\n- on all components: 'adf-container', 'adf-control', 'adf-content', 'adf-error' and 'adf-label'\n- on the form-control-component: 'adf-form-container', 'adf-form-control', 'adf-form-content', 'adf-form-error'\n- on all group-components: 'adf-group-container', 'adf-group-control', 'adf-group-content', 'adf-group-error' and 'adf-group-label'\n- on all array-components: 'adf-array-container', 'adf-array-control', 'adf-array-content', 'adf-array-error' and 'adf-array-label'\n- on all array-header sections: 'adf-header-content'\n- on all array-footer sections: 'adf-footer-content'\n- on the array-item sections: 'adf-array-item' and if the item is selected: 'adf-array-item-selected'\n- for all non-group and non-array-components: 'adf-control-container', 'adf-control-control', 'adf-control-content', 'adf-control-error' and 'adf-control-label'\n\n## Customization\n\n### custom components (DI)\n\nyou can subclass the base class **DynamicFormControlComponentBase**, the generic subclass **DynamicFormControlComponent** or any of the UI-specific subclasses to create your own custom control.\n\nTo be able to refer to this class from the form configuration, your class type must be registered with a new or existing name, which can then be used for the **ControlConfig.controlType** property.\nPlease see **DynamicFormService.setControlComponent** for the registration.\n\nAngulars dependency injection will be used to instantiate your component, so please do not forget to provide **DynamicFormControlComponentBase** using your existing class.\n\n### custom form actions (no DI)\n\nyou can subclass **DynamicFormAction** to create your own dynamic form action.\n\nTo be able to refer to this action from the form configuration, your class type must be registered with a new or existing name, which can then be configured using the **ControlConfig.action** poperty.\nPlease see **DynamicFormService.actionTypes.setType** for the registration.\n\n### custom validators\n\nimplement either **DynamicFormValidatorFn** or **DynamicFormAsyncValidatorFn** and register your function using\n**DynamicFormService.validatorFn.setFn** or **DynamicFormService.asyncValidatorFn.setFn**\n\n## Control-types\n\n| Model | Control | HTML | Material | Nativescript |\n| ----- | ------- | ---- | -------- | ------------ |\n\n\n| ArrayModel:\n| | Array | yes | yes | yes |\n| Group- or Subset-Model:\n| | Fieldset | yes | yes | yes |\n| | Division | yes | yes | yes |\n| | Tabgroup | | yes | |\n| | Stepper | | yes | |\n| ValueControlModel:\n| | Checkbox | yes | yes | yes |\n| | Datepicker | \\* | yes | yes\\*\\* |\n| | Input | yes | yes | yes (TextField) |\n| | Radiogroup | yes | yes | yes |\n| | Select | yes | yes | |\n| | Slider | yes | yes | yes |\n| | Switch | yes | yes | yes |\n| | Textarea | yes | yes | yes (TextView) |\n| | Listpicker | | | yes |\n| NullControlModel:\n| | Button | yes | yes | yes |\n| | Separator | yes | yes | yes |\n| | | | | |\n\n\\*) you can use \"input type='date'\" as replacement for a datepicker\n\n\\*\\*) reports date as utc-timestamp\n\ne.g if timezone is \"Central European Summer Time\" and selected date is \"2018-06-06\"\nthe value of the form control is set to \"2018-06-05T22:00:00.000Z\"\n\n## License\n\n**angular-dynaform** is licensed under the MIT license\n\n[LICENSE](./LICENSE)\n\n## Release Notes\n\n[CHANGELOG](./CHANGELOG.md)\n\n## Contributing\n\n[CONTRIBUTING](./CONTRIBUTING.md)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgms1%2Fangular-dynaform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgms1%2Fangular-dynaform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgms1%2Fangular-dynaform/lists"}