|
@@ -8,25 +8,27 @@ import { TemplateRef } from '@angular/core';
|
|
import { ValidatorFn, AsyncValidatorFn } from '@angular/forms';
|
|
import { ValidatorFn, AsyncValidatorFn } from '@angular/forms';
|
|
import { ValueTransformer } from './../interfaces';
|
|
import { ValueTransformer } from './../interfaces';
|
|
import { standardModifiers, standardTransformer } from './../utils';
|
|
import { standardModifiers, standardTransformer } from './../utils';
|
|
|
|
+import { BehaviorSubject } from 'rxjs';
|
|
|
|
|
|
interface ISimpleFieldMetaData {
|
|
interface ISimpleFieldMetaData {
|
|
- name: string; // The FormControl name
|
|
|
|
- type?: string; // The component type e.g. Text, 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
|
|
|
|
- checkedValue?: boolean|number|string; // Checkboxes and Checkbuttons only
|
|
|
|
- default?: any; // Default value
|
|
|
|
- placeholder?: string; // Optional placeholder text
|
|
|
|
- class?: string | string[]; // CSS classes to apply
|
|
|
|
- id?: string; // CSS id to apply
|
|
|
|
- disabled?: boolean; // Whether field is initially disabled
|
|
|
|
- change?: string; // Name of function in host component to call when value changes
|
|
|
|
- source?: string; // Location in API-returned model - defaults to name
|
|
|
|
- before?: string; // Ordering instruction - move before <name of another key in group>
|
|
|
|
- after?: string; // Ordering instruction - move after <name of another key in group>
|
|
|
|
- validators?: ValidatorFn[]; // Array of validator functions - following Angular FormControl API
|
|
|
|
- asyncValidators?: AsyncValidatorFn[]; // Array of async validator functions - following Angular FormControl API
|
|
|
|
- valFailureMsgs?: StringMap<any>; // Validation failure messages - display appropriate message if validation fails
|
|
|
|
|
|
+ name: string; // The FormControl name
|
|
|
|
+ type?: string; // The component type e.g. Text, 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
|
|
|
|
+ checkedValue?: boolean | number | string; // Checkboxes and Checkbuttons only
|
|
|
|
+ default?: any; // Default value
|
|
|
|
+ placeholder?: string; // Optional placeholder text
|
|
|
|
+ class?: string | string[]; // CSS classes to apply
|
|
|
|
+ id?: string; // CSS id to apply
|
|
|
|
+ disabled?: boolean; // Whether field is initially disabled
|
|
|
|
+ change?: string; // Name of function in host component to call when value changes
|
|
|
|
+ transform?: ValueTransformer //
|
|
|
|
+ source?: string; // Location in API-returned model - defaults to name
|
|
|
|
+ before?: string; // Ordering instruction - move before <name of another key in group>
|
|
|
|
+ after?: string; // Ordering instruction - move after <name of another key in group>
|
|
|
|
+ validators?: ValidatorFn[]; // Array of validator functions - following Angular FormControl API
|
|
|
|
+ asyncValidators?: AsyncValidatorFn[]; // Array of async validator functions - following Angular FormControl API
|
|
|
|
+ valFailureMsgs?: StringMap<any>; // Validation failure messages - display appropriate message if validation fails
|
|
}
|
|
}
|
|
|
|
|
|
interface IOption {
|
|
interface IOption {
|
|
@@ -35,8 +37,8 @@ interface IOption {
|
|
}
|
|
}
|
|
|
|
|
|
interface IOptionsFieldMetaData extends ISimpleFieldMetaData {
|
|
interface IOptionsFieldMetaData extends ISimpleFieldMetaData {
|
|
- options: string[] | IOption[] | (() => IOption[]); // Array of Options - for select, radio-button-group and other 'multiple-choice' types
|
|
|
|
- horizontal?: boolean; // Whether to arrange radio buttons or checkboxes horizontally (default false)
|
|
|
|
|
|
+ options: string[] | IOption[] | (() => IOption[] | BehaviorSubject<IOptionsFieldMetaData['options']>); // Array of Options - for select, radio-button-group and other 'multiple-choice' types
|
|
|
|
+ horizontal?: boolean; // Whether to arrange radio buttons or checkboxes horizontally (default false)
|
|
}
|
|
}
|
|
|
|
|
|
// For components that include links to other pages
|
|
// For components that include links to other pages
|
|
@@ -82,6 +84,7 @@ abstract class SimpleField {
|
|
id?: string;
|
|
id?: string;
|
|
disabled = false;
|
|
disabled = false;
|
|
change?: string;
|
|
change?: string;
|
|
|
|
+ transform?: ValueTransformer;
|
|
validators: ValidatorFn|ValidatorFn[] = [];
|
|
validators: ValidatorFn|ValidatorFn[] = [];
|
|
asyncValidators: AsyncValidatorFn|AsyncValidatorFn[] = [];
|
|
asyncValidators: AsyncValidatorFn|AsyncValidatorFn[] = [];
|
|
valFailureMsgs: StringMap<any> = {};
|
|
valFailureMsgs: StringMap<any> = {};
|
|
@@ -142,15 +145,28 @@ class Option implements IOption {
|
|
}
|
|
}
|
|
|
|
|
|
abstract class OptionsField extends SimpleField {
|
|
abstract class OptionsField extends SimpleField {
|
|
|
|
+
|
|
options: Option[] | (() => Option[]) = [];
|
|
options: Option[] | (() => Option[]) = [];
|
|
- constructor(meta: IOptionsFieldMetaData, context?: any) {
|
|
|
|
|
|
+
|
|
|
|
+ constructor(meta: IOptionsFieldMetaData, private context?: any) {
|
|
super(meta);
|
|
super(meta);
|
|
|
|
+ if (meta.options instanceof BehaviorSubject) {
|
|
|
|
+ meta.options.subscribe(opts => this.constructOptions(opts));
|
|
|
|
+ } else {
|
|
|
|
+ this.constructOptions(meta.options);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private constructOptions(optProvider: IOptionsFieldMetaData['options']) {
|
|
let options;
|
|
let options;
|
|
- if (typeof meta.options === 'function') {
|
|
|
|
- const boundFn = meta.options.bind(context);
|
|
|
|
|
|
+ if (typeof optProvider === 'function') {
|
|
|
|
+ const boundFn = optProvider.bind(this.context);
|
|
options = boundFn();
|
|
options = boundFn();
|
|
|
|
+ if (options instanceof BehaviorSubject) {
|
|
|
|
+ options.subscribe(opts => this.constructOptions(opts));
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
- options = meta.options;
|
|
|
|
|
|
+ options = optProvider;
|
|
}
|
|
}
|
|
if (Array.isArray(options)) {
|
|
if (Array.isArray(options)) {
|
|
this.options = options.reduce((acc, opt) => { acc.push(new Option(opt)); return acc; }, []);
|
|
this.options = options.reduce((acc, opt) => { acc.push(new Option(opt)); return acc; }, []);
|
|
@@ -161,6 +177,7 @@ abstract class OptionsField extends SimpleField {
|
|
];
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
@@ -201,6 +218,7 @@ class CheckboxField extends SimpleField {
|
|
default: any = false;
|
|
default: any = false;
|
|
checkedValue: boolean|number|string = true;
|
|
checkedValue: boolean|number|string = true;
|
|
rowLabel: null;
|
|
rowLabel: null;
|
|
|
|
+ editable: boolean;
|
|
constructor(meta: ISimpleFieldMetaData) {
|
|
constructor(meta: ISimpleFieldMetaData) {
|
|
super(meta);
|
|
super(meta);
|
|
if (meta.default) {
|
|
if (meta.default) {
|
|
@@ -215,9 +233,6 @@ class CheckboxField extends SimpleField {
|
|
if (typeof meta.value === 'undefined') {
|
|
if (typeof meta.value === 'undefined') {
|
|
this.value = this.default; // Get default from this class, not superclass
|
|
this.value = this.default; // Get default from this class, not superclass
|
|
}
|
|
}
|
|
- if (!meta.label) {
|
|
|
|
- this.label = unCamelCase(this.checkedValue.toString());
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -256,8 +271,10 @@ class CheckboxGroup {
|
|
label?: string;
|
|
label?: string;
|
|
groupName: string;
|
|
groupName: string;
|
|
firstEnablesRest?: boolean;
|
|
firstEnablesRest?: boolean;
|
|
|
|
+ editable: boolean = false;
|
|
showAllOrNone?: boolean;
|
|
showAllOrNone?: boolean;
|
|
meta: CheckboxField[] | { [key: string]: CheckboxField };
|
|
meta: CheckboxField[] | { [key: string]: CheckboxField };
|
|
|
|
+ transformer?: ValueTransformer;
|
|
constructor(groupmeta: any) {
|
|
constructor(groupmeta: any) {
|
|
Object.assign(this, groupmeta);
|
|
Object.assign(this, groupmeta);
|
|
if (typeof this.label === 'undefined') {
|
|
if (typeof this.label === 'undefined') {
|
|
@@ -266,13 +283,14 @@ class CheckboxGroup {
|
|
this.label = unCamelCase(this.name);
|
|
this.label = unCamelCase(this.name);
|
|
}
|
|
}
|
|
// Can render as a FormArray or FormGroup depending on input data
|
|
// Can render as a FormArray or FormGroup depending on input data
|
|
|
|
+ const passThrough = { editable: this.editable, transformer: this.transformer };
|
|
if (Array.isArray(groupmeta.meta)) {
|
|
if (Array.isArray(groupmeta.meta)) {
|
|
const arrayMembers = groupmeta.meta;
|
|
const arrayMembers = groupmeta.meta;
|
|
- this.meta = arrayMembers.map(cb => new CheckboxField(cb));
|
|
|
|
|
|
+ this.meta = arrayMembers.map(cb => new CheckboxField({ ...cb, ...passThrough }));
|
|
} else {
|
|
} else {
|
|
const groupMembers = groupmeta.meta;
|
|
const groupMembers = groupmeta.meta;
|
|
this.meta = Object.entries(groupMembers)
|
|
this.meta = Object.entries(groupMembers)
|
|
- .map( ([key, cb]) => [key, new CheckboxField(cb as ISimpleFieldMetaData)] )
|
|
|
|
|
|
+ .map( ([key, cb]: [string, ISimpleFieldMetaData]) => [key, new CheckboxField({ label: unCamelCase(cb.checkedValue || cb.value).toString(), ...cb, ...passThrough })] )
|
|
.reduce((res, [key, cbf]) => { res[key as string] = cbf; return res; }, {});
|
|
.reduce((res, [key, cbf]) => { res[key as string] = cbf; return res; }, {});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -291,7 +309,7 @@ class DatetimeField extends SimpleField {
|
|
value: Date | string;
|
|
value: Date | string;
|
|
constructor(meta) {
|
|
constructor(meta) {
|
|
super(meta);
|
|
super(meta);
|
|
- if (typeof this.value === 'string') {
|
|
|
|
|
|
+ if (typeof this.value === 'string' && this.value) {
|
|
this.value = new Date(this.value);
|
|
this.value = new Date(this.value);
|
|
}
|
|
}
|
|
if (!(this.value instanceof Date)) {
|
|
if (!(this.value instanceof Date)) {
|