Explorar o código

Modeled MetaData Factory now working

Richard Knight %!s(int64=6) %!d(string=hai) anos
pai
achega
90ecd506a1

src/app/_mock/testfields.ts → src/app/_mock/testfields.v1.ts


+ 175 - 0
src/app/_mock/testfields.v2.ts

@@ -0,0 +1,175 @@
+import { ValueTransformer } from './../dynaform/interfaces';
+import { buildModeledMeta } from './../dynaform/libs';
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Native
+
+const basicTextField = {
+	name: 'basicTextField',
+	type: 'text',
+	label: 'Field One',
+	placeholder: 'Type a value here'
+};
+
+const styledTextField = {
+	name: 'styledTextField',
+	type: 'text',
+	placeholder: 'With a DOM id and CSS classes applied',
+	class: ['red', 'bgPaleBlue'],
+	id: 'yoyo'
+};
+
+const textareaField = {
+	name: 'textareaField',
+	type: 'textarea',
+	placeholder: 'Type your long-winded comments here'
+};
+
+const passwordField = {
+	name: 'passwordField',
+	type: 'password',
+	placeholder: 'It\'s a secret'
+};
+
+const selectField = {
+	name: 'selectField',
+	type: 'select',
+	options: ['', 'Apples', 'Oranges', 'Pears', 'Gorgonzola']
+};
+
+const radioField = {
+	name: 'radioField',
+	type: 'radio',
+	options: ['Tea', 'Coffee', 'Cocoa', 'Yerba Maté']
+};
+
+const disabledTextField = {
+	name: 'disabledTextField',
+	type: 'text',
+	placeholder: 'You can\'t touch this',
+	isDisabled: true
+};
+
+const radioFieldHorizontal = {
+	name: 'radioFieldHorizontal',
+	type: 'radio',
+	options: ['Fish', 'Fowl', 'Neither'],
+	horizontal: true
+};
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Custom
+
+const checkbutton = {
+	name: 'checkbutton',
+	type: 'checkbutton',
+	value: '456'
+};
+
+const checkbutton2 = {
+	name: 'checkbutton2',
+	type: 'checkbutton',
+	value: 'Yowsa'
+};
+
+const modifiers = ['Matches', 'Starts With', 'Contains'];
+const transformerFunctions: ValueTransformer = {
+	inputFn: val => {
+		let modifier = 'Starts With';
+		if (/^%.*?%$/.test(val)) {
+			modifier = 'Contains';
+		} else if (/^[^%].*?[^%]$/.test(val)) {
+			modifier = 'Matches';
+		} else if (/^%.*/.test(val)) {
+			modifier = 'Starts With';
+		}
+		const transformedVal = val.replace(/%/g, '').trim();
+		return { modifier: modifier, value: transformedVal };
+	},
+	outputFn: (mod, val) => {
+		let transformedValue;
+		switch (mod) {
+			case 'Starts With':
+				transformedValue = `%${val}`;
+				break;
+			case 'Contains':
+				transformedValue = `%${val}%`;
+				break;
+			case 'Matches':
+			default:
+				transformedValue = val;
+				break;
+		}
+		return transformedValue;
+	}
+};
+const dropdownModifiedInput = {
+	name: 'dropdownModifiedInput',
+	type: 'dropdownModifiedInput',
+	value: 'lovely',
+	modifiers,
+	transform: transformerFunctions
+};
+
+const checkbuttonGroup = {
+	name: 'checkbuttonGroup',
+	type: 'CheckbuttonGroup',
+	firstEnablesRest: true,
+	meta: [{name: 'iMaskTheOthers'}, {name: 'groupMemberTwo'}, {name: 'groupMemberThree'}]
+};
+
+const checkbuttonGroup2 = {
+	name: 'waggaWahWah',
+	type: 'CheckbuttonGroup',
+	firstEnablesRest: true,
+	meta: [{name: 'One'}, {name: 'Two'}, {name: 'Three'}]
+};
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Kendo
+
+const timepicker = {
+	name: 'timepicker',
+	type: 'timepicker'
+};
+
+const datepicker = {
+	name: 'datepicker',
+	type: 'datepicker'
+};
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Container
+
+const container = {
+	name: 'container',
+	type: 'container',
+	meta: {
+		basicTextField,
+		checkbuttonGroup2,
+	}
+};
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+const metadata = {
+	basicTextField,
+	styledTextField,
+	textareaField,
+	passwordField,
+	selectField,
+	radioField,
+	disabledTextField,
+	radioFieldHorizontal,
+	checkbutton,
+	dropdownModifiedInput,
+	checkbuttonGroup,
+	timepicker,
+	datepicker,
+	container
+};
+
+export const formMetaDataObj = buildModeledMeta(metadata);
+
+console.log(formMetaDataObj);

+ 2 - 1
src/app/app.component.ts

@@ -2,7 +2,7 @@ import { Component, OnInit, ViewChild, TemplateRef } from '@angular/core';
 import { FormBuilder, FormGroup } from '@angular/forms';
 import { buildFormGroup } from './dynaform/libs';
 
-import { formMetaDataObj } from './_mock/testfields';
+import { formMetaDataObj } from './_mock/testfields.v2';
 
 @Component({
 	selector: 'app-root',
@@ -27,6 +27,7 @@ export class AppComponent implements OnInit {
 		const fullFormMeta = {
 			dynaformtest: { meta: this.formMetaDataObj }
 		};
+		console.log(fullFormMeta);
 		this.form = buildFormGroup(fullFormMeta);
 		console.log(this.form);
 	}

+ 1 - 6
src/app/dynaform/components/custom/checkbutton/checkbutton.component.ts

@@ -15,7 +15,7 @@ import { CustomInputComponent } from './../../_abstract/custom-input.component';
 	]
 })
 export class CheckbuttonComponent extends CustomInputComponent implements OnChanges {
-	
+
 	exposeMetaInTemplate: string[] = ['label', 'value', 'isDisabled'];
 
 	isChecked: boolean;
@@ -23,11 +23,6 @@ export class CheckbuttonComponent extends CustomInputComponent implements OnChan
 	value?: string | boolean = true;
 	currentValue: string | boolean;
 
-	ngOnInit() {
-		super.ngOnInit();
-		console.log(this.control);
-	}
-
 	ngOnChanges() {
 		this.isDisabled = this.meta.isDisabled;
 	}

+ 1 - 1
src/app/dynaform/components/kendo/datepicker/datepicker.component.html

@@ -1,3 +1,3 @@
-<kendo-datepicker
+<kendo-datepicker class="form-control form-control-sm"
 	[placeholder]="placeholder"
 ></kendo-datepicker>

+ 29 - 6
src/app/dynaform/libs/index.ts

@@ -1,6 +1,7 @@
 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
@@ -31,6 +32,10 @@ const addProp = (obj, key, val) => { obj[key] = val; return obj; };
 // Helper function to distinguish group from field
 const isGroup = metaFoG => metaFoG.meta;
 
+// Is Container
+// Helper function to distinguish container group
+const isContainer = metaFoG => metaFoG.type === 'container';
+
 // ---------------------------------------------------------------------------------------------------------------------
 // Add Missing Names
 // Helper function to add any missing 'name' properties to Fields and Groups using property's key, recursively
@@ -76,25 +81,43 @@ const combineExtraMeta = (metaG, metaExtra) => {
 				combineMetaForField(metaG[key], val);
 		}
 	});
-	return {...metaG, ...combinedMeta};
+	return { ...metaG, ...combinedMeta };
 };
 
 // ---------------------------------------------------------------------------------------------------------------------
 // Build Modelled Metadata - Form Metadata Factory - UNDERWAY
 
+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 = metaF => {
 	// TODO: Add validity check
-	const modeledMetaF = new fmdModels[metaF.type](metaF);
+	const fieldType = buildClassName(metaF.type);
+	if (!fmdModels[fieldType]) {
+		throw new Error('Unknown Field Type');
+	}
+	const modeledMetaF = new fmdModels[fieldType](metaF);
 	return modeledMetaF;
 };
 
 // Build Form Group Member
-const buildModeledGroupMember = metaFoG => isGroup(metaFoG) ? _buildModeledGroup(metaFoG.meta) : buildModeledField(metaFoG);
+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 buildModedMeta = metaG => _buildModeledGroup(metaG);
+const buildModeledMeta = metaG => _buildModeledGroup(metaG);
 
 // ---------------------------------------------------------------------------------------------------------------------
 // Functions which build FormControls and FormGroups
@@ -115,9 +138,9 @@ const buildFormGroupMember = metaFoG => isGroup(metaFoG) ? _buildFormGroup(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(metaG);
+const buildFormGroup = metaG => _buildFormGroup(addMissingNames(metaG));
 
 // ---------------------------------------------------------------------------------------------------------------------
 // Exports
 
-export { autoMeta, combineExtraMeta, buildModedMeta, buildFormGroup };
+export { autoMeta, combineExtraMeta, buildModeledMeta, buildFormGroup };

+ 7 - 5
src/app/dynaform/models/index.ts

@@ -50,7 +50,7 @@ interface TimePickerFieldMetaData extends SimpleFieldMetaData {
 // ---------------------------------------------------------------------------------------------------------------------
 // Base Implementations
 
-class SimpleField {
+abstract class SimpleField {
 	type = 'text';
 	name: string;
 	origin?: string;
@@ -91,15 +91,13 @@ class Option {
 	}
 }
 
-class OptionsField extends SimpleField {
+abstract class OptionsField extends SimpleField {
 	options: Option[] = [];
-	abc;
 	constructor(meta: OptionsFieldMetaData) {
 		super(meta);
 		if (Array.isArray(meta.options)) {
 			this.options = meta.options.reduce((acc, opt) => { acc.push(new Option(opt)); return acc; }, []);
 		}
-		this.abc = true;
 	}
 }
 
@@ -182,11 +180,14 @@ class DatepickerField extends SimpleField {
 	value: Date = new Date();
 }
 
+// ---------------------------------------------------------------------------------------------------------------------
+// Container
+
 class Container {
 	type = 'Dynaform';
 	label = '';
 	template?: TemplateRef<any>;
-	meta: StringMap // TODO: Tighten up on type with union type
+	meta: StringMap; // TODO: Tighten up on type with union type
 	constructor(children: StringMap) {
 		this.meta = children;
 	}
@@ -198,6 +199,7 @@ class Container {
 // Exports
 
 export {
+	SimpleField,
 	TextField, TextareaField, PasswordField, SelectField, RadioField,
 	CheckbuttonField, DropdownModifiedInputField,
 	CheckbuttonGroup,

+ 5 - 0
src/styles.scss

@@ -53,3 +53,8 @@ div.col-sm-8 {
 	display: inline-block;
 	max-width: 140px;
 }
+
+.datepicker {
+	display: inline-block;
+	max-width: 165px;
+}