0.1.1 • Published 3 years ago

@ekisa-cdk/forms v0.1.1

Weekly downloads
-
License
MIT
Repository
github
Last release
3 years ago

@ekisa-cdk/forms

NPM version

Table of contents

Getting started

1. Install package:

npm i @ekisa-cdk/forms

Basic usage

1. Import Form and form controls classes:

import { Form, FormControls, TextBox } from '@ekisa-cdk/forms';

2. Create an instance and pass in a data source that corresponds to the controls that will be rendered:

const dataSource: FormControls = [
  new TextBox(null, {
    key: 'name',
    label: 'Name',
    placeholder: 'Enter your name',
  }),
  new TextBox(null, {
    key: 'lastname',
    label: 'Last name',
    placeholder: 'Enter your last name',
  }),
];

const form = new Form({ dataSource });
form.render();

Form control options

Fieldset

NameTypeDefault value
typeFormControlTypeFieldSet
legendstringundefined
colsColumns1
childrenFormControls[]

TextBox

NameTypeDefault value
typeFormControlTypeTextBox
keystringEmpty
valuestringundefined
labelstringundefined
placeholderstringundefined
validatorsValidatorFn[][]

TextArea

NameTypeDefault value
typeFormControlTypeTextArea
keystringEmpty
valuestringundefined
labelstringundefined
placeholderstringundefined
colsstringundefined
rowsstringundefined
validatorsValidatorFn[][]

NumberBox

NameTypeDefault value
typeFormControlTypeNumberBox
keystringEmpty
valuenumberundefined
labelstringundefined
minnumberundefined
maxnumberundefined
validatorsValidatorFn[][]

SelectBox

NameTypeDefault value
typeFormControlTypeSelectBox
keystringEmpty
valuestringundefined
labelstringundefined
optionsSelectBoxOption[][]
validatorsValidatorFn[][]

SelectBoxOptions

NameTypeDefault value
valuestringundefined
textstringundefined
metastringundefined

CheckBox

NameTypeDefault value
typeFormControlTypeCheckBox
keystringEmpty
valuebooleanundefined
labelstringEmpty
validatorsValidatorFn[][]

RadioGroup

NameTypeDefault value
typeFormControlTypeRadioGroup
keystringEmpty
valuestringundefined
textstringundefined
itemsRadioGroupItem[][]
validatorsValidatorFn[][]

RadioGroupItemOptions

NameTypeDefault value
valuestringundefined
labelstringundefined

DatePicker

NameTypeDefault value
typeFormControlTypeDatePicker
keystringEmpty
valueDateundefined
labelstringundefined
validatorsValidatorFn[][]

TimePicker

NameTypeDefault value
typeFormControlTypeTimePicker
keystringEmpty
valueDateundefined
labelstringundefined
validatorsValidatorFn[][]

Validators

NameInputOutput
requiredN/AValidationErrors
requiredTrueN/AValidationErrors
emailN/AValidationErrors
minmin: numberValidatorFn
maxmax: numberValidatorFn
minLengthminLength: numberValidatorFn
maxLengthmaxLength: numberValidatorFn
patternpattern: RegExpValidatorFn

API options

Get control

Get control by key identifier

Render

Will render the generated form inside some specified target

Arguments | Name | Type | | ------------ | ----------------- | | parent | HTMLBodyElement - HTMLDivElement |

Reset

Reset all form control values to null

Validate

Check the validity of all the configured control validators

Validate Control

Check the validity of a single configured control validators

Arguments | Name | Type | | ---- | ------ | | key | string |

To JSON

Convert controls values to JSON format. You can pass a type to return your data typed.

Generated data-attributes

Data attributes are useful to categorize elements allowing styles customization and tracking the control validity state.

Form

[data-unit-type="Form"]

FieldSet

[data-unit-type="FieldSet"]
[data-unit-type="FieldSetLegend"]

Control Wrapper

[data-unit-type="Wrapper"]
[data-status="valid"]
[data-status="invalid"]
[data-for="::FormControlType::"]

Label

[data-unit-type="Label"]

Validations

[data-unit-type="ValidationsWrapper"]
[data-unit-type="ValidationItem"]

TextBox

[data-unit-type="TextBox"]

TextArea

[data-unit-type="TextArea"]

NumberBox

[data-unit-type="NumberBox"]

SelectBox

[data-unit-type="SelectBox"]
[data-unit-type="SelectBoxOption"]

CheckBox

[data-unit-type="CheckBoxItemWrapper"]
[data-unit-type="CheckBoxItem"]

RadioGroup

[data-unit-type="RadioGroup"]
[data-unit-type="RadioGroupText"]
[data-unit-type="RadioGroupItemWrapper"]
[data-unit-type="RadioGroupItem"]

DatePicker

[data-unit-type="DatePicker"]

TimePicker

[data-unit-type="TimePicker"]

Check the official ValidationsPlugin to see how these attributes can be used or refer to the theming section to see them in action.

Plugins

Plugins are building blocks that extend the form functionality. @ekisa/forms come with built-in plugins that are useful for different purposes and make the integration process seamlessly. There are two types of plugins: internal and external. Internal plugins will run inside the codebase and cannot be modified, although they could be rewritten as custom plugins but would probably need more logic on the implementation side because external plugins cannot listen for events that occur inside the form class. All internal plugins must be passed to the class constructor at the instantiation moment. External plugins whatsoever can be fully replaced by custom plugins and are easy to replicate or modify. All custom plugins are external.

AutoMapper (external)

Automapper is a plugin that will take care for you of all the complex validations between your incoming data and the automatic generation of the data source. To do this you need to create a mapping profile that will tell the plugin how to interpret your models. This plugin is ideal if you need to fetch the questions from a database or another data source and automatically render a form without complex processing in the middle.

Usage

1. Whether you're fetching your data from a relational or non-relational database, define your models to have awareness of the data structure.

export type MySelectBoxModel = {
  valueExpr: string;
  displayExpr: string;
};

export type MyRadioModel = {
  valueExpr: string;
  displayExpr: string;
};

export type MyTextAreaModel = {
  columns: number;
  rows: number;
};

export type MyValidatorModel = {
  type: 'required' | 'email' | 'min' | 'max' | 'minLength' | 'maxLength';
  value?: string;
};

export type MyQuestionType =
  | 'group'
  | 'text'
  | 'textarea'
  | 'number'
  | 'select'
  | 'date'
  | 'time'
  | 'checkbox'
  | 'radio';

export type MyQuestionModel = {
  dataField: string;
  controlType: MyQuestionType;
  label?: string;
  placeholder?: string;
  rules?: Array<MyValidatorModel>;
  textareaOptions?: MyTextAreaModel;
  selectboxOptions?: Array<MySelectBoxModel>;
  radioOptions?: Array<MyRadioModel>;
};

export type MyGroupModel = {
  type: 'fieldset';
  title: string;
  columns: number;
  questions: Array<MyQuestionModel>;
};

export type MyFormModel = Array<MyQuestionModel | MyGroupModel>;

2. Create a mapping profile

This will tell the plugin how to map your model inside the form

import { AutoMapperPluginConfig } from '@ekisa-cdk/forms';

const mappingProfile: AutoMapperPluginConfig<MyQuestionType> = {
  types: {
    FieldSet: 'group',
    TextBox: 'text',
    TextArea: 'textarea',
    NumberBox: 'number',
    SelectBox: 'select',
    CheckBox: 'checkbox',
    RadioGroup: 'radio',
    DatePicker: 'date',
    TimePicker: 'time',
  },
  keys: {
    controlTypePropertyName: 'controlType', // bound to MyQuestionModel -> controlType
    fieldSet: {
      // bound to MyGroupModel
      legend: 'title',
      cols: 'columns',
      children: 'questions',
    },
    control: {
      // bound to MyQuestionModel
      key: 'dataField',
      value: 'value',
      label: 'label',
      placeholder: 'placeholder',
      validators: 'rules',
    },
    textAreaOptions: {
      // bound to MyTextAreaModel
      cols: 'cols',
      rows: 'rows',
    },
    numberBoxOptions: {
      // bound to MyNumberBoxModel
      min: 'min',
      max: 'max',
    },
    selectBoxOptions: {
      // bound to MySelectBoxModel
      options: 'selectboxOptions',
      value: 'valueExpr',
      text: 'displayExpr',
      meta: 'meta',
    },
    radioGroupOptions: {
      // bound to MyRadioModel
      text: 'label',
      items: 'radioOptions',
      value: 'valueExpr',
      label: 'displayExpr',
    },
    validators: {
      // bound to MyValidatorModel
      propertyName: 'rules',
      name: 'name',
      value: 'value',
    },
  },
};

3. Create an instance of the AutoMapperPlugin, pass in your questions, and the mapping profile. Lastly, run the plugin to get the generated data source

const mapper = new AutoMapperPlugin<MyQuestionType>(questions, mappingProfile);
const dataSource = mapper.run();

4. Pass in the data source to the form constructor

const form = new Form({ dataSource }}

See full implementation in the Examples section

Events (external)

A flexible plugin that allows you to easily attach events to a form control

Usage

1. Create an instance of the EventsPlugin

const eventsPlugin = new EventsPlugin();

2. Attach the event to any control by key

eventsPlugin.run({
  targetKey: control.key,
  attachmentType: 'multiple',
  on: 'change',
  runFn: () => console.log(`Triggered`),
});

Options

NameTypeDescription
targetKeystringControl key identifier
attachmentTypesingle - multipleIf control is composed of multiple child controls, you must specify multiple (eg. RadioGroup), otherwise single
onkeyof HTMLElementEventMapEvent name
runFn(this: Element, ev: Event) => voidEvent callback where you must write your custom logic

See full implementation in the Examples section

Validations (internal)

This plugin will run inside the form to detect when it is invalid and change the data-status attribute depending on the validity status. It will also append the validation messages automatically in each control wrapper.

Usage

1. Instantiate the Form class and pass in the ValidationsPlugin as argument:

const form = new Form({
  someDataSource,
  plugins: [
    new ValidationsPlugin({
      messages: {
        required: 'Campo obligatorio',
        requiredTrue: 'Debe aceptar la política de tratamiento de datos',
        email: 'El correo electrónico es inválido',
        min: 'El valor {1} es incorrecto: mínimo permitido es {0}',
        max: 'El valor {1} es incorrecto: máximo permitido es {0}',
        minLength: 'longitud {1} es incorrecta: mínimo permitido es {0}',
        maxLength: 'longitud {1} es incorrecta: máximo permitido es {0}',
      },
    }),
  ],
});

Options

NameTypeDescription
parentElementkeyof HTMLElementTagNameMapParent HTML element that will be appended to the control wrapper
childElementkeyof HTMLElementTagNameMapChild HTML element that will be appended to the parent element
messagesValidationMessagesGlobal messages for each validation type

ValidationMessages options

NameDescriptionFormat
requiredMessage for required validatorN/A
requiredTrueMessage for required true validatorN/A
emailMessage for email validatorN/A
minMessage for min validator{0} to access current value, {1} to access established value
maxMessage for max validator{0} to access current value, {1} to access established value
minLengthMessage for minLength validator{0} to access current value, {1} to access established value
maxLengthMessage for maxLength validator{0} to access current value, {1} to access established value

See full implementation in the Examples section

Custom (external)

You can easily create a plugin that extends the form functionality and solves a repetitive task that's not included by default; for this, there's a simple interface that you can implement in order to have some constraints inside your implementation.

Usage

To create a custom plugin you just need to define a new class and implement de FormPlugin interface

import { FormPlugin } from '@ekisa-cdk/forms';

export class SendEmailPlugin implements FormPlugin<YourConfigType> {
  run(input: YourConfigType): void {
    // your logic to send email after some event
  }
}
import { FormPlugin } from '@ekisa-cdk/forms';

export class CssPlugin implements FormPlugin<YourConfigType> {
  run(input: YourConfigType): void {
    // your logic to add css classes to elements
  }
}

Theming

This library doesn't have any styling at all and that's intended since the design is expected to be fully customizable. Currently, there are two ways to design your form.

  1. You can easily customize your form using the auto-generated data attributes explained in the data attributes section. See example

  2. You can create a custom plugin to add CSS classes to each element at rendering time.

Examples

Angular

To do

Create examples

- [ ] Create vanilla example
- [x] Create Angular example
- [ ] Create Svelte example
- [ ] Create Vue example
- [ ] Create React example

License

MIT License © 2021 Ekisa Team

0.1.1

3 years ago

0.1.0

3 years ago

0.0.7

3 years ago

0.0.5

3 years ago

0.0.4

3 years ago

0.0.3

3 years ago

0.0.2

3 years ago

0.0.1

3 years ago

0.0.0

3 years ago