|
@@ -1,18 +1,17 @@
|
|
|
-import { FormBuilder, FormControl } from '@angular/forms';
|
|
|
+import { FormBuilder, FormGroup, FormControl } from '@angular/forms';
|
|
|
import { reduce } from 'lodash/fp';
|
|
|
import * as fmdModels from './../models';
|
|
|
-import { Container } from '@angular/compiler/src/i18n/i18n_ast';
|
|
|
|
|
|
/*
|
|
|
- * FORM UTILITIES
|
|
|
+ * FORM METADATA UTILITIES
|
|
|
*
|
|
|
* Exports
|
|
|
* -------
|
|
|
* autoMeta(model) - generate basic metadata from a raw or mapped model, recursively if necessary
|
|
|
* combineExtraMeta(metadata, extraMeta) - combine extra metadata into metatdata, lazyly and recursively
|
|
|
* combineModelWithMeta(model, extraMeta) - automatically generated metadata for model then combines extra metadata
|
|
|
- * buildModedMeta(metadata) - use field metadta models to fill out metadata
|
|
|
- * buildFormGroup(metadata) - builds FormGroups from modelled metdata, recursively if necessary
|
|
|
+ * buildFieldSpecificMeta(metadata) - use field metadata models to expand metadata
|
|
|
+ * buildFormGroupFunctionFactory(fb) - return a function to buildFormGroups using the supplied FormBuilder singleton
|
|
|
*
|
|
|
* Variable names
|
|
|
* --------------
|
|
@@ -22,40 +21,9 @@ import { Container } from '@angular/compiler/src/i18n/i18n_ast';
|
|
|
*
|
|
|
*/
|
|
|
|
|
|
-const fb = new FormBuilder();
|
|
|
-
|
|
|
-// ---------------------------------------------------------------------------------------------------------------------
|
|
|
-// Helper Funstions
|
|
|
-
|
|
|
-const addProp = (obj, key, val) => { obj[key] = val; return obj; };
|
|
|
-
|
|
|
-// Is Group
|
|
|
-// Helper function to distinguish group from field
|
|
|
-const isGroup = metaFoG => metaFoG.meta;
|
|
|
-
|
|
|
-// Is Container
|
|
|
-// Helper function to distinguish container group (a group of child fields)
|
|
|
-const isContainer = metaFoG => isGroup(metaFoG) && (metaFoG.type === 'container' || typeof metaFoG.type === 'undefined');
|
|
|
-
|
|
|
-// ---------------------------------------------------------------------------------------------------------------------
|
|
|
-// Add Missing Names
|
|
|
-// Helper function to add any missing 'name' properties to Fields and Groups using property's key, recursively
|
|
|
-// MAYBE NOT NEEDED?
|
|
|
-
|
|
|
-const addNameIfMissing = (metaFoG, key) => metaFoG.name ? metaFoG : addProp(metaFoG, 'name', key);
|
|
|
-const addNameToSelfAndChildren = ( [key, metaFoG] ) => {
|
|
|
- metaFoG = addNameIfMissing(metaFoG, key);
|
|
|
- if (isGroup(metaFoG)) {
|
|
|
- metaFoG.meta = addMissingNames(metaFoG.meta); // Recursion
|
|
|
- }
|
|
|
- return [key, metaFoG];
|
|
|
-};
|
|
|
-const addMissingNames = metaG => Object.entries(metaG)
|
|
|
- .map(addNameToSelfAndChildren)
|
|
|
- .reduce((res, [key, val]) => addProp(res, key, val), {});
|
|
|
-
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
// Raw Model (or Mapped Raw Model) to Automatic Metadata
|
|
|
+// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
const isScalar = val => typeof val === 'boolean' || typeof val === 'number' || typeof val === 'string';
|
|
|
|
|
@@ -69,13 +37,15 @@ const autoMeta = model => Object.entries(model)
|
|
|
.map(keyValPairToMetaRecursive)
|
|
|
.reduce((res, [key, val]) => addProp(res, key, val), {});
|
|
|
|
|
|
+
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
// Combine automatically generated metadata with overrides
|
|
|
+// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
-const combineMetaForField = (metaF, metaFextra) => Object.assign(metaF, metaFextra);
|
|
|
-const combineExtraMeta = (metaG, metaExtra) => {
|
|
|
+const combineMetaForField = (metaF, extraMetaF) => Object.assign(metaF, extraMetaF);
|
|
|
+const combineExtraMeta = (metaG, extraMeta) => {
|
|
|
const combinedMeta = {};
|
|
|
- Object.entries(metaExtra).forEach(([key, val]) => {
|
|
|
+ Object.entries(extraMeta).forEach(([key, val]) => {
|
|
|
if (typeof metaG[key] === 'object') {
|
|
|
combinedMeta[key] = (<any>val).meta ?
|
|
|
combineMetaForField(metaG[key], { meta: combineExtraMeta(metaG[key].meta, (<any>val).meta) }) :
|
|
@@ -85,15 +55,15 @@ const combineExtraMeta = (metaG, metaExtra) => {
|
|
|
return { ...metaG, ...combinedMeta };
|
|
|
};
|
|
|
|
|
|
-// ---------------------------------------------------------------------------------------------------------------------
|
|
|
-// Combine model with overrides
|
|
|
+// Combine model with overrides (after automatically generating metadata from the model)
|
|
|
+const combineModelWithMeta = (model, extraMeta) => combineExtraMeta(autoMeta(model), extraMeta);
|
|
|
|
|
|
-const combineModelWithMeta = (model, metaExtra) => combineExtraMeta(autoMeta(model), metaExtra);
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
-// Build Modelled Metadata - Form Metadata Factory
|
|
|
+// Build Form-Field-Type-Specific Metadata (using the field models in dynaform/models)
|
|
|
+// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
-const buildClassName = (t = 'text') => {
|
|
|
+const buildFieldClassName = (t = 'text') => {
|
|
|
const start = t[0].toUpperCase() + t.slice(1);
|
|
|
if (start === 'Container' || t.slice(-5) === 'Group') {
|
|
|
return start;
|
|
@@ -103,7 +73,7 @@ const buildClassName = (t = 'text') => {
|
|
|
|
|
|
const buildModeledField = metaFoG => {
|
|
|
const type = isContainer(metaFoG) ? 'container' : metaFoG.type;
|
|
|
- const className = buildClassName(type);
|
|
|
+ const className = buildFieldClassName(type);
|
|
|
if (!fmdModels[className]) {
|
|
|
throw new Error(`No metadata model "${className}" for type "${type}"`);
|
|
|
}
|
|
@@ -111,50 +81,86 @@ const buildModeledField = metaFoG => {
|
|
|
};
|
|
|
|
|
|
// Build Form Group Member
|
|
|
-const buildModeledGroupMember = metaFoG => {
|
|
|
+const buildModeledFieldGroupMember = metaFoG => {
|
|
|
const modeledGroupMember = buildModeledField(metaFoG);
|
|
|
if (isContainer(metaFoG)) {
|
|
|
- modeledGroupMember.meta = _buildModeledGroup(metaFoG.meta);
|
|
|
+ modeledGroupMember.meta = _buildModeledFieldGroup(metaFoG.meta);
|
|
|
}
|
|
|
return modeledGroupMember;
|
|
|
};
|
|
|
|
|
|
// Build Form Group
|
|
|
-const buildModeledGroupReducerIteree = (res, metaFoG) => Object.assign(res, { [metaFoG.name]: buildModeledGroupMember(metaFoG) });
|
|
|
-const _buildModeledGroup = metaG => reduce(buildModeledGroupReducerIteree, {}, metaG);
|
|
|
-const buildModeledMeta = metaG => _buildModeledGroup(metaG);
|
|
|
+const buildModeledFieldGroupReducerIteree = (res, metaFoG) => Object.assign(res, { [metaFoG.name]: buildModeledFieldGroupMember(metaFoG) });
|
|
|
+const _buildModeledFieldGroup = metaG => reduce(buildModeledFieldGroupReducerIteree, {}, metaG);
|
|
|
+const buildFieldSpecificMeta = metaG => _buildModeledFieldGroup(metaG);
|
|
|
+
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
-// Functions which build FormControls and FormGroups
|
|
|
-
|
|
|
-// Build Form Control
|
|
|
-// TODO: Flesh out function to build validators
|
|
|
-const buildControlState = metaF => ({ value: metaF.value || metaF.default, disabled: metaF.isDisabled });
|
|
|
-const buildValidators = metaF => ({
|
|
|
- validators: null,
|
|
|
- asyncValidators: null,
|
|
|
- updateOn: 'blur'
|
|
|
-});
|
|
|
-const buildFormControl = metaF => new FormControl(buildControlState(metaF) /*, buildValidators(metaF) */);
|
|
|
+// Build FormGroups
|
|
|
+// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
-// Build Form Group Member
|
|
|
-const buildFormGroupMember = metaFoG => isGroup(metaFoG) ? _buildFormGroup(metaFoG.meta) : buildFormControl(metaFoG);
|
|
|
+const buildFormGroupFunctionFactory = (fb: FormBuilder): (meta) => FormGroup => {
|
|
|
+ // Establishes a closre over the supplied FormBuilder and returns a function that builds FormGroups from metadata
|
|
|
+ // ( it's done this way so we can use the FormBuilder singleton without reinitialising )
|
|
|
+
|
|
|
+ // Build Form Control
|
|
|
+ // TODO: Flesh out function to build validators
|
|
|
+ const buildControlState = metaF => ({ value: metaF.value || metaF.default, disabled: metaF.isDisabled });
|
|
|
+ const buildValidators = metaF => ({
|
|
|
+ validators: null,
|
|
|
+ asyncValidators: null,
|
|
|
+ updateOn: 'blur'
|
|
|
+ });
|
|
|
+ const buildFormControl = metaF => new FormControl(buildControlState(metaF) /*, buildValidators(metaF) */);
|
|
|
|
|
|
-// Build Form Group
|
|
|
-const buildFormGroupReducerIteree = (res, metaFoG) => Object.assign(res, { [metaFoG.name]: buildFormGroupMember(metaFoG) });
|
|
|
-const _buildFormGroup = metaG => fb.group(reduce(buildFormGroupReducerIteree, {}, metaG));
|
|
|
-const buildFormGroup = metaG => _buildFormGroup(addMissingNames(metaG));
|
|
|
+ // Build Form Group Member
|
|
|
+ const buildFormGroupMember = metaFoG => isGroup(metaFoG) ?
|
|
|
+ _buildFormGroup(metaFoG.meta) :
|
|
|
+ buildFormControl(metaFoG);
|
|
|
+
|
|
|
+ const buildFormGroupReducerIteree = (res, metaFoG) => Object.assign(res, { [metaFoG.name]: buildFormGroupMember(metaFoG) });
|
|
|
+ const _buildFormGroup = _metaG => fb.group(reduce(buildFormGroupReducerIteree, {}, _metaG));
|
|
|
|
|
|
+ const buildFormGroup = metaG => {
|
|
|
+ const metaWithNames = addMissingNames(metaG);
|
|
|
+ return _buildFormGroup(metaWithNames);
|
|
|
+ };
|
|
|
+ return buildFormGroup;
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+// ---------------------------------------------------------------------------------------------------------------------
|
|
|
+// Helper Funstions
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
-// Convenience Functions combining several steps
|
|
|
|
|
|
-const autoBuildModeledMeta = (model, metaExtra = {}) => buildModeledMeta(combineModelWithMeta(model, metaExtra));
|
|
|
-const autoBuildFormGroup = (model, metaExtra = {}) => buildFormGroup(autoBuildModeledMeta(model, metaExtra));
|
|
|
+// Add Property to object
|
|
|
+const addProp = (obj, key, val) => { obj[key] = val; return obj; };
|
|
|
+
|
|
|
+// Is Group
|
|
|
+// Helper function to distinguish group from field
|
|
|
+const isGroup = metaFoG => metaFoG.meta;
|
|
|
+
|
|
|
+// Is Container
|
|
|
+// Helper function to distinguish container group (a group of child fields)
|
|
|
+const isContainer = metaFoG => isGroup(metaFoG) && (metaFoG.type === 'container' || typeof metaFoG.type === 'undefined');
|
|
|
+
|
|
|
+// Add Missing Names
|
|
|
+// Helper function to add any missing 'name' properties to Fields and Groups using property's key, recursively
|
|
|
+const addNameIfMissing = (metaFoG, key) => metaFoG.name ? metaFoG : addProp(metaFoG, 'name', key);
|
|
|
+const addNameToSelfAndChildren = ( [key, metaFoG] ) => {
|
|
|
+ metaFoG = addNameIfMissing(metaFoG, key);
|
|
|
+ if (isGroup(metaFoG)) {
|
|
|
+ metaFoG.meta = addMissingNames(metaFoG.meta); // Recursion
|
|
|
+ }
|
|
|
+ return [key, metaFoG];
|
|
|
+};
|
|
|
+const addMissingNames = metaG => Object.entries(metaG)
|
|
|
+ .map(addNameToSelfAndChildren)
|
|
|
+ .reduce((res, [key, val]) => addProp(res, key, val), {});
|
|
|
+
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
// Exports
|
|
|
+// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
-export {
|
|
|
- autoMeta, combineModelWithMeta, combineExtraMeta, buildModeledMeta, buildFormGroup,
|
|
|
- autoBuildModeledMeta, autoBuildFormGroup
|
|
|
-};
|
|
|
+export { autoMeta, combineModelWithMeta, combineExtraMeta, buildFieldSpecificMeta, buildFormGroupFunctionFactory };
|