This should not be used any where but we are prefering to use ngx-formerly. Dynamic form generator, creates Angular Reactive forms from json schema
Install Package
npm i --save @labshare/ngx-forms
Add import to the main module
import { NgxFormsModule } from '@labshare/ngx-forms';
@NgModule({
imports: [
NgxFormsModule
]
})
Add html tag with bindings
<dynamic-form [formConfig]="config" #form="dynamicForm" [model]="data"></dynamic-form>
{{ form.group.value | json }}
config
- json array that contains fields definitionsmodel
- Input data. One way binding only
Add reference in the component controller
export class MyFormComponent {
public data = { title: "Test" };
public config = {
fields: [
{ type: "text", label: "Title", name: "title" },
{ type: "text", label: "Project Name", name: "projectName", placeholder: "Enter project name", minLength: 2, maxLength: 5 },
{ type: "select", label: "Type", name: "select", options: ["one", "two", "three"] }
]
};
}
ngx-forms can be extended with custom layout or custom inputs
export const customFields = {
peoplePicker: PeoplePickerComponent,
};
export const customLayouts: LayoutDictionary = {
myCustomLayout: CustomLayoutComponent,
};
@NgModule({
imports: [
ReactiveFormsModule,
FormsModule,
CommonModule,
NgxFormsModule.forRoot({
layoutDictionary: customLayouts,
fieldDictionary: customFields,
}),
],
declarations: [PeoplePickerComponent],
entryComponents: [CustomLayoutComponent, PeoplePickerComponent],
})
export class NgxFormsExtensionsModule {}
then use custom fields and layouts in the form config:
{
layout: 'myCustomLayout',
fields: [
{ type: 'text', label: 'Title', name: 'title' },
{ type: 'peoplePicker', label: 'People', name: 'people' },
]
};
ngAfterViewInit() {
this.formReference.changes.subscribe(val => {
console.log('from observable', val)
});
}
Custom layout component needs to extend BaseLayout
from ngx-forms
:
import { Component } from '@angular/core';
import { BaseLayout } from '@labshare/ngx-forms/src/app/layouts/base-layout';
@Component({
selector: 'custom-forms-layout',
template: require('./custom-layout.component.html'),
})
export class CustomLayoutComponent extends BaseLayout {}
Custom layout template must have entry directive dynamicField
through which an input will be injected:
<div class="row">
<div class="col-12">
<div *ngFor="let field of formConfig.fields" class="mb-2">
<ng-container *ngIf="!field.hidden">
<label>{{field.label}}
</label>
<div dynamicField [field]="field" [group]="group" [model]="model"></div>
</ng-container>
</div>
</div>
</div>
Inputs can be of any kind and return objects, arrays, strings etc.
Creating and field itself is not difficult but in most cases you may have to create a custom ControlValueAccessor
Custom field must implement Field
interface from ngx-forms
import {Component} from '@angular/core';
import {FormGroup} from '@angular/forms';
import {FieldConfig, Field} from '@labshare/ngx-forms';
@Component({
selector: 'field-editor',
template: require('./field-editor.component.html'),
})
export class PeoplePickerComponent implements Field {
public field: FieldConfig;
public group: FormGroup;
}
And template:
<ng-container [formGroup]="group">
<people-picker-accessor [options]="field.options" [formControlName]="field.name"></people-picker-accessor>
</ng-container>
In this case people-picker-accessor
is a custom ControlValueAccessor
It is possible to overwrite existing out of the box fields and layouts by simply using their names in the dictionary in forRoot
. For example if you need to overwrite text
input field:
export const customFields = {
text: PeoplePickerComponent,
};
Name | Type | Description | Example |
---|---|---|---|
disabled? |
boolean |
disable field if true |
disabled: true |
label? |
string |
field label | label: "Project Title" |
name |
string |
field name | name: "projectTitle" |
options? |
string[] |
options for <select> dropdown |
options: [ "Option 1", "Option 2" ] |
placeholder? |
string |
text placeholder | placeholder: "Enter Project Title" |
type |
string |
field type (see field type description) | type: "select" |
value? |
any |
field value | value: 123 |
required? |
boolean |
Validation: required or not | required: true |
minLength? |
number |
Validation: minimum length of a text field | minLength: 5 |
maxLength? |
number |
Validation: maximum length of a text field | maxLength: 12 |
email? |
boolean |
Validation: field must be an email address | email: true |
min? |
number |
Validation: minumum value for number fields | min: 100 |
max? |
number |
Validation: maximum value for number fields | max: 1000 |
pattern? |
RegExp |
Validation: regular expression | pattern: "^[a-zA-Z0-9_]*$" |
nullValidator? |
any |
Validation: null validation | nullValidator: true |
hidden |
boolean |
hide the field by default when the form loading | hidden: true |
text
- text input<input type="text">
select
- text input<select>
textarea
- text input<textarea>
hidden
- hidden value field<input type="hidden">
.radio
- radio buttonscheckbox
- checkbox buttonsdate
- datepicker