ng-deco-forms

1.0.1 • Public • Published

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.

Readme

Keywords

Package Sidebar

Install

npm i ng-deco-forms

Weekly Downloads

7

Version

1.0.1

License

MIT

Unpacked Size

55.7 kB

Total Files

65

Last publish

Collaborators

  • inonkp