123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /* *********************************************************************************************************************
- * MetaData models for Form Fields
- * -------------------------------
- * Keep in one file for now, but maybe split if this grows too large
- ******************************************************************************************************************** */
- import { TemplateRef } from '@angular/core';
- import { ValidatorFn, AsyncValidatorFn } from '@angular/forms';
- import { ValueTransformer } from './../interfaces';
- import { standardModifiers, standardTransformer } from './../utils';
- interface SimpleFieldMetaData {
- name: string; // The FormControl name
- origin?: string; // Location in API-returned model - defaults to name
- type?: string; // The component type e.g. BasicInput, Checkbutton, Timepicker, etc
- label?: string; // The field label - defaults to unCamelCased name if not supplied
- value?: any; // The field value - defaults to empty string if not supplied
- default?: any; // Default value
- placeholder?: string; // Optional placeholder text
- class?: string | Array<string>; // CSS classes to apply
- id?: string; // CSS id to apply
- isDisabled?: boolean; // Whether field is initially disabled
- validators?: Array<ValidatorFn>; // Array of validator functions - following Angular FormControl API
- asyncValidators?: Array<AsyncValidatorFn>; // Array of async validator functions - following Angular FormControl API
- valFailureMsgs?: StringMap; // Validation failure messages - display appropriate message if validation fails
- }
- interface Option {
- label: string;
- value: string | number | boolean;
- }
- interface OptionsFieldMetaData extends SimpleFieldMetaData {
- options; // Array of Options - for select, radio-button-group and other 'multiple-choice' types
- horizontal?: boolean; // Whether to arrang radio buttons or checkboxes horizontally (default false)
- }
- // For components that include links to other pages
- interface Link {
- label: string;
- route: any[] | string;
- }
- interface DropdownModifiedInputFieldMetaData extends SimpleFieldMetaData {
- modifiers: string[];
- transform: ValueTransformer;
- }
- interface TimePickerFieldMetaData extends SimpleFieldMetaData {
- // TODO: Tighhten up on types
- value: Date;
- format: string;
- steps: StringMap;
- }
- // Utility to unCamelCase
- const unCamelCase = (str: string): string => str.replace(/([A-Z])/g, ' $1')
- .replace(/(\w)(\d)/g, '$1 $2')
- .replace(/^./, s => s.toUpperCase());
- // ---------------------------------------------------------------------------------------------------------------------
- // Form Field MetaData Models
- // ---------------------------------------------------------------------------------------------------------------------
- // Base Implementations
- abstract class SimpleField {
- type: string;
- name: string;
- origin?: string;
- label?: string;
- value;
- default = '';
- placeholder = '';
- class?: string | Array<string>;
- id?: string;
- isDisabled = false;
- validators: Array<ValidatorFn> = [];
- asyncValidators: Array<AsyncValidatorFn> = [];
- valFailureMsgs: StringMap = {};
- constructor(meta: SimpleFieldMetaData) {
- Object.assign(this, meta);
- if (!this.origin) {
- // If origin is not supplied it's the same as the name
- this.origin = this.name;
- }
- if (!this.label) {
- // If label is not supplied set it to the unCamelCased'n'Spaced name
- // e.g. supervisorCardNumber --> Supervisor Card Number
- this.label = unCamelCase(this.name);
- }
- }
- }
- class Option {
- // Can take a simple string value, a value-label pair [value, label],
- // or an Option of the form { label: string, value: string }
- constructor(opt: string | string[] | Option) {
- if (typeof opt === 'object') {
- if (Array.isArray(opt)) {
- this.label = opt[1];
- this.value = opt[0];
- } else {
- this.label = opt.label;
- this.value = opt.value;
- }
- } else if (typeof opt === 'string') {
- this.label = opt;
- this.value = opt;
- }
- }
- }
- abstract class OptionsField extends SimpleField {
- options: Option[] = [];
- constructor(meta: OptionsFieldMetaData) {
- super(meta);
- if (Array.isArray(meta.options)) {
- this.options = meta.options.reduce((acc, opt) => { acc.push(new Option(opt)); return acc; }, []);
- } else {
- this.options = [
- new Option({ label: 'Yes', value: true }),
- new Option({ label: 'No', value: false })
- ];
- }
- }
- }
- // ---------------------------------------------------------------------------------------------------------------------
- // Concrete Implementations - Native Form Components
- class TextField extends SimpleField {
- type = 'Text';
- link?: Link;
-
- }
- class TextareaField extends SimpleField {
- type = 'Textarea';
- }
- class PasswordField extends SimpleField {
- type = 'Password';
- }
- class SelectField extends OptionsField {
- type = 'Select';
- link?: Link;
- }
- class RadioField extends OptionsField {
- type = 'Radio';
- }
- class HiddenField extends SimpleField {
- type = 'Hidden';
- }
- // ---------------------------------------------------------------------------------------------------------------------
- // Concrete Implementations - Custom Form Components
- class CheckbuttonField extends SimpleField {
- type = 'Checkbutton';
- default: any = false;
- }
- class DropdownModifiedInputField extends SimpleField {
- type = 'DropdownModifiedInput';
- modifiers: string[] = standardModifiers;
- transform: ValueTransformer = standardTransformer;
- constructor(meta: DropdownModifiedInputFieldMetaData) {
- super(meta);
- }
- }
- // ---------------------------------------------------------------------------------------------------------------------
- // Concrete Implementations - Custom FormGroup Components (which render a group of FormControls)
- class CheckbuttonGroup {
- type = 'CheckbuttonGroup';
- name: string;
- label?: string;
- groupName: string;
- firstEnablesRest?;
- showAllOrNone?;
- meta: CheckbuttonField[] | { [key: string]: CheckbuttonField };
- constructor(groupmeta: any) {
- Object.assign(this, groupmeta);
- if (!this.label) {
- // If label is not supplied set it to the unCamelCased'n'Spaced name
- // e.g. supervisorCardNumber --> Supervisor Card Number
- this.label = unCamelCase(this.name);
- }
- // Can render as a FormArray or FormGroup depending on input data
- if (Array.isArray(groupmeta.meta)) {
- const arrayMembers = groupmeta.meta;
- this.meta = arrayMembers.map(cb => new CheckbuttonField(cb));
- } else {
- const groupMembers = groupmeta.meta;
- this.meta = Object.entries(groupMembers)
- .map( ([key, cb]) => [key, new CheckbuttonField(cb as SimpleFieldMetaData)] )
- .reduce((res, [key, cbf]) => { res[<string>key] = cbf; return res; }, {});
- }
- }
- }
- // ---------------------------------------------------------------------------------------------------------------------
- // Concrete Implementations - Kendo Form Components
- class TimepickerField<TimePickerFieldMetaData> extends SimpleField {
- type = 'Timepicker';
- value: Date = new Date();
- format = 'hh:mm a';
- steps = { hour: 1, minute: 15 };
- }
- class DatepickerField extends SimpleField {
- type = 'Datepicker';
- value: Date = new Date();
- }
- // ---------------------------------------------------------------------------------------------------------------------
- // Container
- class Container {
- type = 'Container';
- name: string;
- label = '';
- template?: TemplateRef<any>;
- meta: StringMap; // TODO: Tighten up on type with union type
- constructor(meta: StringMap) {
- console.log(meta);
- meta.meta ? Object.assign(this, meta) : this.meta = meta;
- if (!this.label) {
- this.label = unCamelCase(this.name);
- }
- }
- }
- // ---------------------------------------------------------------------------------------------------------------------
- // Button Group
- interface ButtonInterface {
- label: string;
- fnId: string;
- class?: string;
- icon?: string;
- }
- class Button implements ButtonInterface {
- label;
- fnId;
- class: string = 'btn-primary';
- constructor(buttonProps) {
- Object.assign(this, buttonProps);
- }
- }
- class ButtonGroup {
- type = 'ButtonGroup';
- name: string;
- label = '';
- meta: Button[];
- readonly noFormControls = true; // Indicates this has no FormControls associated with it
- constructor(meta) {
- Object.assign(this, meta);
- this.meta = this.meta.map(b => b instanceof Button ? b : new Button(b));
- }
- }
- // ---------------------------------------------------------------------------------------------------------------------
- // ---------------------------------------------------------------------------------------------------------------------
- // ---------------------------------------------------------------------------------------------------------------------
- // Exports
- export {
- SimpleField,
- TextField, TextareaField, PasswordField, SelectField, RadioField, HiddenField,
- CheckbuttonField, DropdownModifiedInputField,
- CheckbuttonGroup,
- TimepickerField, DatepickerField,
- Container, ButtonGroup
- };
|