Angular Dynamic Form Generator
Richard Knight 77b18f120b README typo | 4 år sedan | |
---|---|---|
_notes | 6 år sedan | |
e2e | 6 år sedan | |
src | 4 år sedan | |
.editorconfig | 6 år sedan | |
.gitignore | 6 år sedan | |
README.md | 4 år sedan | |
angular.json | 6 år sedan | |
karma.conf.js | 6 år sedan | |
ng-dynaform.code-workspace | 5 år sedan | |
package-lock.json | 5 år sedan | |
package.json | 5 år sedan | |
protractor.conf.js | 6 år sedan | |
tsconfig.json | 6 år sedan | |
tslint.json | 6 år sedan | |
yarn.lock | 6 år sedan |
A Dynamic Form Builder for Angular, with built in model mapper.
Define forms with metadata, or build directly from models
Combine metadata with models to populate form values
Group related fields in containers, to any level of nesting
Use repeating containers to model complex arrays
Take advantage of terse metadata, and sensible defaults
Import the Dynaform module.
import { NgModule } from '@angular/core';
...
import { DynaformModule } from './dynaform/dynaform.module';
...
@NgModule({
imports: [
...
DynaformModule
...
]
...
})
export class AppModule { }
In any component where you want to generate a form, import and then inject DynaformService
.
import { Component } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { DynaformService } from './dynaform'; // Paths may vary
@Component({
selector: 'some-formy-thing',
templateUrl: './some-formy-thing.component.html',
styleUrls: ['./some-formy-thing.component.scss']
})
export class SomeFormyThingComponent implements OnInit {
form: FormGroup;
meta: StringMap<any>;
constructor(private dynaform: DynaformService) {
}
Build the form from your model, your metadata, or a combination of the two.
ngOnInit() {
const model = { firstName: 'Olly', lastName: 'October', country: 'France' };
const meta = {
country: { type: 'select', options: ['France', 'Germany', 'Norway', 'Sweden'] }
}
// Build FormGroup and Modeled Metadata
const { form, modeledMeta } = this.dynaform.build(model, meta);
}
Dynaform supports two build strategies: MODELFISRT and METAFIRST (the default)
MODELFIRST generates a form from the supplied model, and by default will ignore any metadata points that don't occur in the model. If you supply no metadata all fields will render as text inputs.
METAFIRST generates a form from the supplied metadata, and by default will ignore any data in the model that doesn't have a corresponding metadata entry.
You can set the build strategy by calling setBuildStrategy
this.dynaform.setBuildStrategy('MODELFIRST');
The behaviour of the MODELFIRST build strategy can be further modified by supplying true
as the third parameter to dynaform.build
, where true means "create extra fields from metadata, even when they don't occur ion the model". It's useful when the model might be incomplete.
// Build FormGroup and Modeled Metadata, creating fields for any points mentioned in
// the metadata that don't occur in the model
const { form, modeledMeta } = this.dynaform.build(model, meta, true);
change
handler of any field.// Register callbacks (probably in ngOnInit)
this.dynaform.register({
'SAYHELLO': this.sayHello,
'SAYCHEESE': this.sayCheese
}, this);
Then later in the component...
handleCallback(fnId) {
this.dynaform.call(fnId);
}
sayHello() {
alert('HELLO');
}
sayCheese() {
alert('CHEESE');
}
All fields support the following metadata. The missing properties will be 'filled in' by dynaform's field-specific models, allowing forms to specifiued tersely.
Property | Description | Default / Notes |
---|---|---|
name |
The FormControl name | Do not set. Derived automatically from the key of the metadata object. |
type |
The control's type | Text |
label |
The controls's label | An unCamelCased and spaced version of name |
value |
The control's initial value | Empty string. May be set from model, overriding the default |
checkedValue |
Value when checked* | Checkboxes / Checkbuttons only |
default |
The control's default value | |
placeholder |
Optional placeholder text | |
class |
CSS class(es) to apply | Single class (string) or array of classes (string[]) |
id |
CSS id to apply | |
disabled |
Whether field is disbled | false |
change |
Name of function in host component to call when value changes | |
source |
Location of data in model | Defaults to the same name and path. Used by model-mapper. |
before |
Ordering instruction - move before name of another control in group | |
after |
Ordering instruction - move after name of another control in group | |
validators |
Array of validator functions - following Angular FormControl API | [] |
asyncValidators |
Array of async validator functions - following Angular FormControl API | [] |
valFailureMessages |
Validation failure messages - used to display appropriate message if validation fails |
(for selects, radios, checkbutton groups, etc)
Options can be specified as an array of values, an array of [value, label] pairs, or an array of objects with the structure { value: 'VAL', label: 'My label' }. If you supply a a simple array of values, each value is used as both the value and label.
{
firstName: {},
lastName: {},
telephoneNumber: {},
country: { type: 'select', options: ['France', 'Germany', 'Italy', 'Norway'] }
}
{
cheeseLover: { type: 'checkbox', label: 'Do you like cheese?' },
favouriteCheese: {
type: 'radio',
label: 'What`s your favourite?',
options: [
['CHED', 'Cheddar'],
['WENS', 'Wensleydale'],
['BRIE', 'Brie'],
['GORG', 'Gorgonzola']
]
}
}
TO ADD.
e.g. radio, horizontal.
Related fields can be grouped using containers. A container has it's own meta
property, under which the fields it contains are defined in the usual way. Containers can even contain other containers, with no hard limit on depth, although in practice you'll probably not need to use deeply nested metadata.
cheeseMakersContract and cheeseMakersAddress are both containers...
{
optIn: { label: 'Become a cheese maker?', type: 'checkbutton' },
optInConfirm: { label: 'Really?', type: 'radio', options: ['Yes', 'No', 'Maybe'] },
cheeseMakersContract: {
label: 'Contract details',
meta: {
type: { label: 'Contract type' },
startDate: { type: 'datepicker' }
cheeseMakersAddress: {
label: 'Address'
meta: {
address1: {},
address2: {},
city: {},
postcode: { class: 'short-field' }
}
}
}
}
};
Property | Description | Default / Notes |
---|---|---|
name |
The FormGroup name | Do not set. Derived automatically from the key of the metadata object. |
label |
Optional container label | Creates a heading above the container |
seed |
An object containing key-value pairs, used to seed metadata for all contained fields | Use when all or most fields share certain properties, e.g. to apply the same class or default |
template |
Optional template override | This should be an Angular TemplateRef See https://angular.io/api/core/TemplateRef |
TO ADD.
TO ADD.
TO ADD.
TO ADD.
TO ADD.
TO ADD.
TO ADD.