|
@@ -0,0 +1,162 @@
|
|
|
+/***********************************************************************************************************************
|
|
|
+ * MetaData models for Form Fields
|
|
|
+ * -------------------------------
|
|
|
+ * Keep in one file for now, but maybe split if this grows too large
|
|
|
+ **********************************************************************************************************************/
|
|
|
+
|
|
|
+import { ValidatorFn, AsyncValidatorFn } from '@angular/forms';
|
|
|
+import { ValueTransformer } from '@components/dropdown-modified-input/dropdown-modified-input.component';
|
|
|
+
|
|
|
+// ---------------------------------------------------------------------------------------------------------------------
|
|
|
+// Types & Interfaces
|
|
|
+
|
|
|
+type Option = {
|
|
|
+ label: string,
|
|
|
+ value: string
|
|
|
+}
|
|
|
+
|
|
|
+interface BasicFieldMetaData {
|
|
|
+ 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?: string // The field value - defaults to empty string if not supplied
|
|
|
+ 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 OptionsFieldMetaData extends BasicFieldMetaData {
|
|
|
+ options: Option[] // Array of Options - for select, radio-button-group and other 'multiple-choice' types
|
|
|
+}
|
|
|
+
|
|
|
+interface DropdownModifiedInputFieldMetaData extends OptionsFieldMetaData {
|
|
|
+ modifiers: string[]
|
|
|
+ transform: ValueTransformer
|
|
|
+}
|
|
|
+
|
|
|
+interface TimePickerFieldMetaData extends BasicFieldMetaData {
|
|
|
+ // To add...
|
|
|
+}
|
|
|
+
|
|
|
+// ---------------------------------------------------------------------------------------------------------------------
|
|
|
+// Form Field MetaData Models
|
|
|
+
|
|
|
+class BasicField
|
|
|
+{
|
|
|
+ name: string;
|
|
|
+ origin?: string;
|
|
|
+ type: string = 'Basicinput';
|
|
|
+ label?: string;
|
|
|
+ value: string = '';
|
|
|
+ placeholder: string = '';
|
|
|
+ class?: string | Array<string>;
|
|
|
+ isDisabled?: boolean;
|
|
|
+ validators: Array<ValidatorFn> = [];
|
|
|
+ asyncValidators: Array<AsyncValidatorFn> = [];
|
|
|
+ valFailureMsgs: StringMap = {};
|
|
|
+
|
|
|
+ constructor(meta: BasicFieldMetaData) {
|
|
|
+ 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 = this.name.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase());
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class OptionsField extends BasicField
|
|
|
+{
|
|
|
+ options: Option[];
|
|
|
+ constructor(meta: OptionsFieldMetaData) {
|
|
|
+ super(meta);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class DropdownModifiedInputField extends OptionsField
|
|
|
+{
|
|
|
+ modifiers: string[]
|
|
|
+ transform: ValueTransformer;
|
|
|
+ constructor(meta: DropdownModifiedInputFieldMetaData) {
|
|
|
+ super(meta);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class TimePickerField extends BasicField
|
|
|
+{
|
|
|
+ // To add...
|
|
|
+ constructor(meta: TimePickerFieldMetaData) {
|
|
|
+ super(meta);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ---------------------------------------------------------------------------------------------------------------------
|
|
|
+// Exports
|
|
|
+
|
|
|
+export { BasicField, OptionsField, DropdownModifiedInputField, TimePickerField };
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/***********************************************************************************************************************
|
|
|
+ * Usage
|
|
|
+ * Just ideas here for reference at the moment
|
|
|
+ **********************************************************************************************************************/
|
|
|
+
|
|
|
+/*
|
|
|
+ (1) Approach 1: Loop through model and 'lazily generate' the metadata. Something like...
|
|
|
+
|
|
|
+ overrides = {
|
|
|
+ field3: {
|
|
|
+ type: Chechkbutton,
|
|
|
+ label: 'Friendly Name'
|
|
|
+ }
|
|
|
+ }
|
|
|
+modeledMeta = {};
|
|
|
+for (field in model) {
|
|
|
+ if (field in overrides) {
|
|
|
+ Object.assign(modeledMeta, FieldFactory(model, overrides[field])); // FieldFactory returns a new field model of the specified type
|
|
|
+ } else {
|
|
|
+ Object.assign(modeledMeta, new BasicField(field)); // Defauls to basic text field
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ (2) Apprach 2: Meta-data fully specified (not lazily-generated), so loop through metadata genetating field models
|
|
|
+ metaspec may be hard-coded (for now) or loaded from server and cached, as part of app boostraping
|
|
|
+
|
|
|
+ metaspac = {
|
|
|
+ // Meta-data spec
|
|
|
+ }
|
|
|
+ modeledMeta = {}
|
|
|
+ for (field in metaspec) {
|
|
|
+ Object.assign(modeledMeta, FieldFactory(model, metaspec[field]));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ ...
|
|
|
+ Then pass modeledMeta to dynamic form generator / layout, etc
|
|
|
+
|
|
|
+ /*
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|