123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- import { FormBuilder, 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
- *
- * 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
- * buildModedMeta(metadata) - use field metadta models to fill out metadata
- * buildFormGroup(metadata) - builds FormGroups from modelled metdata, recursively if necessary
- *
- * Variable names
- * --------------
- * metaF = metadata for Field
- * metaG = metadata for Group (possibly nested)
- * metaFoG = metadata for Field Or Group
- *
- */
- 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';
- const keyValPairToMeta = (val, key) => ({ name: key, [isScalar(val) ? 'value' : 'meta']: val });
- const keyValPairToMetaRecursive = ( [key, val] ) => {
- const innerVal = isScalar(val) ? val : autoMeta(val);
- const metaVal = keyValPairToMeta(innerVal, key);
- return [key, metaVal];
- };
- 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 combinedMeta = {};
- Object.entries(metaExtra).forEach(([key, val]) => {
- if (typeof metaG[key] === 'object') {
- combinedMeta[key] = (<any>val).meta ?
- combineMetaForField(metaG[key], { meta: combineExtraMeta(metaG[key].meta, (<any>val).meta) }) :
- combineMetaForField(metaG[key], val);
- }
- });
- return { ...metaG, ...combinedMeta };
- };
- // ---------------------------------------------------------------------------------------------------------------------
- // Build Modelled Metadata - Form Metadata Factory
- const buildClassName = (t = 'text') => {
- const start = t[0].toUpperCase() + t.slice(1);
- if (start === 'Container' || t.slice(-5) === 'Group') {
- return start;
- }
- return start + 'Field';
- };
- const buildModeledField = metaFoG => {
- const type = isContainer(metaFoG) ? 'container' : metaFoG.type;
- const className = buildClassName(type);
- if (!fmdModels[className]) {
- throw new Error(`No metadata model "${className}" for type "${type}"`);
- }
- return new fmdModels[className](metaFoG);
- };
- // Build Form Group Member
- const buildModeledGroupMember = metaFoG => {
- const modeledGroupMember = buildModeledField(metaFoG);
- if (isContainer(metaFoG)) {
- modeledGroupMember.meta = _buildModeledGroup(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);
- // ---------------------------------------------------------------------------------------------------------------------
- // 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 Form Group Member
- const buildFormGroupMember = metaFoG => isGroup(metaFoG) ? _buildFormGroup(metaFoG.meta) : buildFormControl(metaFoG);
- // 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));
- // ---------------------------------------------------------------------------------------------------------------------
- // Exports
- export { autoMeta, combineExtraMeta, buildModeledMeta, buildFormGroup };
|