ng-deco-forms
v1.0.1
Published
A forms library for Angular. Relying heavily on Angular's dependency injection mechanism makes this library incredibly flexible. Form fields are entirely described via Typescript decorators, making forms easier to maintain. Loosely inspired by Formly.
Downloads
44
Readme
Angular Decorated Forms
A forms library for Angular. Relying heavily on Angular's dependency injection mechanism makes this library incredibly flexible. Form fields are entirely described via Typescript decorators, making forms easier to maintain. Loosely inspired by Formly.
Table of contents
Basic Examples
Field Examples
Text Input
export class TextTypeComponent {
constructor(@Inject(FIELD_FORM_CONTROL_TOKEN) public control: FormControl) {
}
}
<input
class="deco-text"
type="text"
[formControl]="control"
>
Number Input
export class NumberTypeComponent {
constructor(@Inject(FIELD_FORM_CONTROL_TOKEN) public control: FormControl,
@Optional() @Inject(FIELD_CONFIG_TOKEN) public config: NumberFieldConfig) {
}
}
<input
class="deco-number"
type="number"
[formControl]="control"
[step]="config.step"
[min]="config.min"
[max]="config.max"
>
Label Wrapper
export class FieldLabelWrapperComponent {
constructor(
@Optional() @Inject(FIELD_CONFIG_TOKEN) public config: LabelConfig
) {
}
}
<div class="deco-field-label">
<div class="deco-field-label__label">
<label
*ngIf="config.label"
class="deco-field-label__text"
>{{ config.label }}</label>
</div>
<div class="deco-field-label__field">
<ng-content></ng-content>
</div>
</div>
Simple Usage
Create a field:
export const Text = () => DecoField(TextTypeComponent)
Or with config:
export const Number = (props?: NumberFieldConfig) => DecoField(NumberTypeComponent, props)
Create a form:
@Form()
class DemoForm {
@Text()
my_text = "Bla Bla"
@Number({step: 2})
my_number = 1
}
Render your form:
const demo = new DemoForm()
<ng-container [deco-form]="form"></ng-container>
Add Wrappers
Create a wrapper:
const LabelWrapper = Wrap(FieldLabelWrapperComponent)
Make a propertry for it:
const LabelProp = (label: string) => Prop(FieldLabelWrapperComponent, 'label', label)
Use it:
@Form()
class DemoForm {
@LabelProp('Your Opinion')
@LabelWrapper()
@Text()
my_text = "Bla Bla"
@LabelProp('Your Contribution')
@LabelWrapper()
@Number({step: 2000})
my_number = 1
}
Or chain them together:
const Label = (label: string) => chain([
LabelWrapper, LabelProp(label)
])
@Form()
class DemoForm {
@Label('Your Opinion')
@Text()
my_text = "Bla Bla"
@Label('Your Contribution')
@Number({step: 2000})
my_number = 1
}
Add CSS Classes
@Class('form-class') // adds a css class to the form component element
@Form(SubmitComponent)
class DemoForm {
@Class('text-class') // adds a css class to the text component element
@Text()
my_text = "Bla Bla"
}
Providers
Use providers to inject your component with built-in or custom tokens.
const MAX_LENGTH_TOKEN = new InjectionToken<number>('max-length')
@Form()
class DemoForm {
@Provide({provide: MAX_LENGTH_TOKEN, useValue: 50})
@Text()
my_text = "Bla Bla"
}
And in TextTypeComponent
export class TextTypeComponent {
constructor(@Inject(MAX_LENGTH_TOKEN) public maxLength: Number) {
}
}
Chaining Decorators
Sometimes you want to chain decorators to make the easier to use or understand.
const Label = (label: string) => chain([
Wrap(FieldLabelWrapperComponent),
Prop(FieldLabelWrapperComponent,'label', label)
])
@Form(SubmitComponent)
class DemoForm {
@Label('Label')
@Text()
my_text = "Bla Bla"
}
Usage Details
Form Controls
Deco Forms uses Reactive Forms as its primary source of control. You have access to the form control's through FIELD_FORM_CONTROL_TOKEN.
export class NumberTypeComponent {
constructor(@Inject(FIELD_FORM_CONTROL_TOKEN) public control: FormControl) {
}
}
Props
If you component can be configured, add a field called config in the constructor.
export class NumberTypeComponent {
constructor(@Optional() @Inject(FIELD_CONFIG_TOKEN) public config: NumberFieldConfig) {
}
}
Use Prop for single properties and Props for multiple properties.
const Label = (label: string) => Prop(FieldLabelWrapperComponent, 'label', label)
const LabelProps = (props: {label: string, labelColor: Color}) => Props(FieldLabelWrapperComponent, props)
Decorator Order
Decorator order is important. Props, Prop, Class and Providers will apply on the last component, be it a field or a wrapper.
API
Decorators
Form
Decorate classes with Form to enable deco forms to render it. Receives a root component to render the form. Optionally accepts a component to render, defaults to GroupComponent.
DecoField
Use DecoField(Component) on a class memeber to render it using Component. Its initial value will be the value assigned to it.
Group
Use Group on class members to render another class. This can be thought of as grouping inputs using FormGroup.
Wrap
Use Wrap(Component) to wrap fields with Component. Wrapper components should use ng-content.
Class
Assigns CSS classes to the last component in the decorator chain.
Provide
Assign providers to be injected into components. These will be added to the last components in the decorator chain.
Listen
Receives a factory function that returns a function, which listen to form control changes. Can decorate groups as well.
Components
Form
To create a new form:
<deco-form [form-target]="form"></deco-form>
Where "form" is a class annotated with @Form
Group
To create a new group within a form tree:
<deco-group></deco-group>
Directives
Form Directive
If you know what your doing you can render the form without DecoFormComponent with:
<ng-container [deco-form]="formTarget"></ng-container>
Field Directive
You can render fields with:
<ng-container [deco-field]="formTarget"></ng-container>
Tokens
The library supplies some tokens to be used:
FORM_FIELDS_TOKEN - gives you access to the fields in a custom Group.
FIELD_FORM_CONTROL_TOKEN - gives you the form control of a field.
FIELD_PARENT_CONTROL_TOKEN - gives you the parent control of a field.
FIELD_PROP_KEY_TOKEN - gives the name of the field form control.
FIELD_CONFIG_TOKEN - the config of a field.
FIELD_CHANGE_TRACKING_TOKEN - Use this to provide a function that will trigger on field changes.
FORM_SUBMIT_TOKEN - Controls what happensn when a form submits.
Implementations
Bootstrap Implementation and Demo
Check out the bootstrap implementation and a Live Demo.