Forráskód Böngészése

Fixing CheckbocGroup and CheckbuttonGroup for use with arrays of scalars

Richard Knight 4 éve
szülő
commit
985caa696d

+ 63 - 0
src/app/_mock/testfields.v17.ts

@@ -0,0 +1,63 @@
+// ---------------------------------------------------------------------------------------------------------------------
+// TESTS: container groups? again
+// ---------------------------------------------------------------------------------------------------------------------
+
+import { Validators as V } from '@angular/forms';
+
+const model = {};
+
+const meta = {
+	general: {
+		label: 'Genaral Details',
+		source: '/',
+		meta: {
+			name: { validators: V.required },
+			description: { type: 'textarea' },
+			duration: { },
+			unit: { label: 'Time Unit' }
+		}
+	},
+	email: {
+		label: 'Email Configuration',
+		source: '/',
+		meta: {
+			emailTo: { label: 'To', validators: [ V.required, V.email ] },
+			emailCc: { 
+				minRepeat: 1,
+				maxRepeat: 5,
+				initialRepeat: 1,
+				showAddControl: true,
+				showDeleteControl: true,
+				validators: V.email
+			},
+			emailBcc: { 
+				minRepeat: 1,
+				maxRepeat: 5,
+				initialRepeat: 1,
+				showAddControl: true,
+				showDeleteControl: true,
+				validators: V.email
+			},
+			subject: { validators: V.required },
+			message: { type: 'textarea' }
+		}
+	},
+	report: {
+		label: 'Report Configuration',
+		source: '/',
+		meta: {
+			table: {
+				type: 'select',
+				options: [ 'AAA', 'BBB' ],
+				validators: V.required
+			},
+			columns: {
+				source: '/',
+				type: 'checkboxGroup',
+				meta: ['Ab', 'Cd', 'Ef', 'Ghi']
+			}
+		}
+	}
+};
+
+export { model, meta };

+ 14 - 3
src/app/_mock/testfields.v8.ts

@@ -14,16 +14,15 @@ const meta = {
 	cbFormArray: { type: 'CheckbuttonGroup', showAllOrNone: 1 }
 };
 
-
 /*
 const model = {};
 
 const meta = {
 	cbFormArray: {
-		type: 'CheckbuttonGroup',
+		type: 'CheckboxGroup',
 		showAllOrNone: 1,
 		meta: [
-			{ label: 'A', value: 'A' },
+			{ value: 'A', label: 'Ahoy there' },
 			{ value: 'B' },
 			{ value: 'C' },
 			{ value: 'D' },
@@ -33,4 +32,16 @@ const meta = {
 };
 */
 
+/*
+const model = {};
+
+const meta = {
+	cbFormArray: {
+		type: 'CheckboxGroup',
+		showAllOrNone: 1,
+		meta: [ 'A', 'B', 'C', 'D', 'E' ]
+	}
+};
+*/
+
 export { model, meta };

+ 1 - 1
src/app/app.component.html

@@ -4,7 +4,7 @@
 			<h1>NgDynaform: Clarity Edition</h1>
 			<p>
 			<b>Dynamic Form Layout Module</b><br>
-			Load different tests by appending a query param to the URL <b>?test=N</b> (where N is a number between 1 and 16).<br>
+			Load different tests by appending a query param to the URL <b>?test=N</b> (where N is a number between 1 and 17).<br>
 			NOTE: Model set to update on change, but this can be set to blur or submit for less re-rendering.
 			</p>
 			<br>

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

@@ -18,8 +18,9 @@ import * as test13 from './_mock/testfields.v13';
 import * as test14 from './_mock/testfields.v14';
 import * as test15 from './_mock/testfields.v15';
 import * as test16 from './_mock/testfields.v16';
+import * as test17 from './_mock/testfields.v17';
 
-const testdata = [ test1, test2, test3, test4, test5, test6, test7, test8, test9, test10, test11, test12, test13, test14, test15, test16 ];
+const testdata = [ test1, test2, test3, test4, test5, test6, test7, test8, test9, test10, test11, test12, test13, test14, test15, test16, test17 ];
 
 const defatltTest = 1;
 

+ 3 - 3
src/app/dynaform/components/group/checkbox-group/clr-checkbox-group.component.html

@@ -1,6 +1,6 @@
-<div class="aba-checkbutton-group" [formGroup]="formGroup">
-	<app-checkbox *ngFor="let groupMember of controlNames; let i = index"
-		[formControlName]="groupMember"
+<div class="aba-checkbutton-group">
+	<app-checkbox *ngFor="let control of formGroup.controls; let i = index"
+		[control]="control"
 		[meta]="childMetaArray[i]"
 	>
 	</app-checkbox>

+ 1 - 1
src/app/dynaform/components/group/checkbox-group/clr-checkbox-group.component.ts

@@ -11,7 +11,7 @@ export class ClrCheckboxGroupComponent extends GroupInputComponent implements On
 
 	firstControl: FormControl;
 
-	readonly componentName = 'ClrCheckboxGroupComponent'; // For AOT compatibility, as class names don't survive minification
+	readonly componentName = 'CheckboxGroupComponent'; // For AOT compatibility, as class names don't survive minification
 
 	constructor(
 		@Attribute('firstEnablesRest') private firstEnablesRest,

+ 4 - 4
src/app/dynaform/dynaform.component.html

@@ -20,14 +20,14 @@
 				<div *ngSwitchCase="'RepeatingField'" class="dyna-rf-container">
 					<div *ngFor="let field of meta.meta; let i = index" class="dyna-rf-field">
 						<button *ngIf="meta.showDeleteControl"
-							class="btn btn-sm btn-icon btn-outline-danger dyna-rep-btn-delete"
+							class="dyna-rep-btn-delete"
 							[disabled]="!deleteAllowed(meta.name)"
 							(click)="deleteRepeatingMember(meta.name, i)">
 							<clr-icon shape="trash"></clr-icon>
 						</button>
 						<ng-container *ngTemplateOutlet="dynafield; context: getRepeatingTemplateContext(meta.name, i)"></ng-container>
 					</div>
-					<div *ngIf="meta.showAddControl">
+					<div *ngIf="meta.showAddControl" class="dyna-rep-add-container">
 						<button
 							class="btn btn-sm btn-icon btn-outline-success dyna-rep-btn-add"
 							[disabled]="!addAllowed(meta.name)"
@@ -67,7 +67,7 @@
 						</button>
 						<ng-container *ngTemplateOutlet="dynaform; context: getRepeatingTemplateContext(meta.name, i)"></ng-container>
 					</div>
-					<div *ngIf="meta.showAddControl && meta.display === 'ALL'">
+					<div *ngIf="meta.showAddControl && meta.display === 'ALL'" class="dyna-rep-add-container">
 						<button
 							class="btn btn-sm btn-icon btn-outline-success dyna-rep-btn-add"
 							[disabled]="!addAllowed(meta.name)"
@@ -96,7 +96,7 @@
 <ng-template let-control="control" let-meta="meta" #dynaform>
 	<div [ngClass]="getRowClass(control, meta)">
 		<h3 *ngIf="meta.label" class="h-dyna" [ngClass]="'h-dyna-' + (path.length + 2)">{{ meta.label }}</h3>
-		<app-dynaform [formGroup]="control" [meta]="meta.meta" [template]="template" [ngClass]="{ 'dyna-hidden': !meta.focussed }" (call)="handleCallback($event)"></app-dynaform>
+		<app-dynaform [formGroup]="control" [meta]="meta.meta" [template]="template" [ngClass]="getEmbeddedDynaformClasses(meta)" (call)="handleCallback($event)"></app-dynaform>
 	</div>
 </ng-template>
 

+ 10 - 0
src/app/dynaform/dynaform.component.ts

@@ -132,6 +132,16 @@ export class DynaformComponent implements OnInit, OnChanges {
 		return path;
 	}
 
+	getEmbeddedDynaformClasses(meta): StringMap<boolean> {
+		let ngClassObj = { 'dyna-hidden': !meta.focussed };
+		if (Array.isArray(meta.class)) {
+			ngClassObj = (meta.class as string[]).reduce((acc, className) => (acc[className] = true, acc), ngClassObj);
+		} else if (typeof meta.class === 'string' && meta.class) {
+			ngClassObj[meta.class] = true;
+		}
+		return ngClassObj;
+	}
+
 	isField(meta: StringMap<any>): boolean {
 		return !meta.type.includes('Container') && meta.type !== 'RepeatingField';
 	}

+ 8 - 4
src/app/dynaform/models/field.model.ts

@@ -87,6 +87,9 @@ abstract class SimpleField {
 	valFailureMsgs: StringMap<any> = {};
 
 	constructor(meta: ISimpleFieldMetaData, context?: any) {
+		if (typeof meta !== 'object') {
+			return;
+		}
 		Object.assign(this, meta);
 		if (!this.source) {
 			// If source is not supplied it's the same as the name
@@ -213,7 +216,7 @@ class CheckboxField extends SimpleField {
 			this.value = this.default; // Get default from this class, not superclass
 		}
 		if (!meta.label) {
-			meta.label = unCamelCase(this.checkedValue.toString());
+			this.label = unCamelCase(this.checkedValue.toString());
 		}
 	}
 }
@@ -254,7 +257,7 @@ class CheckboxGroup {
 	groupName: string;
 	firstEnablesRest?: boolean;
 	showAllOrNone?: boolean;
-	meta: CheckbuttonField[] | { [key: string]: CheckbuttonField };
+	meta: CheckboxField[] | { [key: string]: CheckboxField };
 	constructor(groupmeta: any) {
 		Object.assign(this, groupmeta);
 		if (typeof this.label === 'undefined') {
@@ -265,11 +268,11 @@ class CheckboxGroup {
 		// Can render as a FormArray or FormGroup depending on input data
 		if (Array.isArray(groupmeta.meta)) {
 			const arrayMembers = groupmeta.meta;
-			this.meta = arrayMembers.map(cb => new CheckbuttonField(cb));
+			this.meta = arrayMembers.map(cb => new CheckboxField(cb));
 		} else {
 			const groupMembers = groupmeta.meta;
 			this.meta = Object.entries(groupMembers)
-				.map( ([key, cb]) => [key, new CheckbuttonField(cb as ISimpleFieldMetaData)] )
+				.map( ([key, cb]) => [key, new CheckboxField(cb as ISimpleFieldMetaData)] )
 				.reduce((res, [key, cbf]) => { res[key as string] = cbf; return res; }, {});
 		}
 	}
@@ -277,6 +280,7 @@ class CheckboxGroup {
 
 class CheckbuttonGroup extends CheckboxGroup {
 	type = 'CheckbuttonGroup';
+	meta: CheckbuttonField[] | { [key: string]: CheckbuttonField };
 }
 
 // ---------------------------------------------------------------------------------------------------------------------

+ 10 - 5
src/app/dynaform/services/_formdata-utils.ts

@@ -26,6 +26,7 @@
 import { FormBuilder, FormGroup, FormArray, FormControl, AbstractControl, AbstractControlOptions } from '@angular/forms';
 import { cloneDeep, omit, reduce } from 'lodash/fp';
 import * as fmdModels from '../models/field.model';
+import { meta } from '@mock/testfields.v1';
 
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -47,7 +48,7 @@ const keyValPairToMetaRecursive = ( [key, val] ) => {
 
 const arrayToMeta = array => array.map((val, i) => {
 	if (isScalar(val)) {
-		return { name: `item${i + 1}`, 'value' : val };
+		return { name: `item${i + 1}`, value : val, label: val };
 	} else {
 		return { name: `group${i + 1}`, meta: autoMeta(val) };
 	}
@@ -721,7 +722,7 @@ const isRepeating = (metaFoG): boolean => !!(metaFoG.minRepeat || metaFoG.maxRep
 
 // Is Repeating Field
 // Helper function to distinguish a repeating field (a field that can be repeated 1...N times)
-const isRepeatingField = (metaRF): boolean => metaRF.type && metaRF.type.toLowerCase() === 'repeatingfield'
+const isRepeatingField = (metaRF): boolean => typeof metaRF.type === 'string' && metaRF.type.toLowerCase() === 'repeatingfield'
 	|| (
 		!metaRF.type
 		&& isRepeating(metaRF)
@@ -735,7 +736,7 @@ const isRepeatingField = (metaRF): boolean => metaRF.type && metaRF.type.toLower
 
 // Is Container
 // Helper function to distinguish container group (a group of child fields)
-const isContainer = (metaFoG): boolean => metaFoG.type && metaFoG.type.toLowerCase() === 'container'
+const isContainer = (metaFoG): boolean => typeof metaFoG.type === 'string' && metaFoG.type.toLowerCase() === 'container'
 	|| (
 		!metaFoG.type
 		&& hasMeta(metaFoG)
@@ -744,7 +745,7 @@ const isContainer = (metaFoG): boolean => metaFoG.type && metaFoG.type.toLowerCa
 
 // Is Repeating Container
 // Helper function to distinguish a repeating container group (a group of child fields that can be repeated 1...N times)
-const isRepeatingContainer = (metaFoG): boolean => metaFoG.type && metaFoG.type.toLowerCase() === 'repeatingcontainer'
+const isRepeatingContainer = (metaFoG): boolean => typeof metaFoG.type === 'string' && metaFoG.type.toLowerCase() === 'repeatingcontainer'
 	|| (
 		!metaFoG.type
 		&& isRepeating(metaFoG)
@@ -761,7 +762,11 @@ const addNameIfMissing = (metaFoG, key) => metaFoG.name ? metaFoG : addProp(meta
 const addNameToSelfAndChildren = ( [key, metaFoG] ) => {
 	metaFoG = addNameIfMissing(metaFoG, key);
 	if (hasMeta(metaFoG) && !isRepeatingContainer(metaFoG)) {
-		metaFoG.meta = isArray(metaFoG.meta) ? Object.values(addMissingNames(metaFoG.meta)) : addMissingNames(metaFoG.meta); // Recursion
+		if (metaFoG.meta.length && metaFoG.meta.every(isScalar)) {
+			metaFoG.meta = metaFoG.meta.map(val => ({ name: val, value: val }));
+		} else {
+			metaFoG.meta = isArray(metaFoG.meta) ? Object.values(addMissingNames(metaFoG.meta)) : addMissingNames(metaFoG.meta); // Recursion
+		}
 	}
 	return [key, metaFoG];
 };