浏览代码

Repeating Containers finally working

Richard Knight 6 年之前
父节点
当前提交
150ce15db2

+ 1 - 1
src/app/_mock/testfields.v12.ts

@@ -20,7 +20,7 @@ const model = {
 
 const meta = {
 	repeating: {
-		label: 'Repating Group',
+		label: 'Repeating Group',
 		seed: { class: 'short-field' },
 		minRepeat: 1,
 		maxRepeat: 5,

+ 1 - 1
src/app/_mock/testfields.v7.ts

@@ -9,7 +9,7 @@ import { delay, map } from 'rxjs/internal/operators';
 const testAsyncValidator = (fc: FormControl): Observable<ValidationErrors> => {
 	return of(fc).pipe(delay(2000)).pipe(map(_fc => {
 		console.log('Async validator got', _fc.value);
-		return { is42: _fc.value === '42' };
+		return { isNot42: _fc.value.trim() !== '42' };
 	}));
 };
 

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

@@ -50,6 +50,7 @@ export class AppComponent implements OnInit, OnChanges {
 		console.log('Model', model);
 		console.log('Meta', meta);
 
+		/*
 		console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
 
 		// Test autoMeta
@@ -71,6 +72,7 @@ export class AppComponent implements OnInit, OnChanges {
 		console.log(fg);
 
 		console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+		*/
 
 		// Build the FormGroup and Modeled Metadata from the imported test data
 		const dynaformdata = this.dynaform.build(model, meta, true);

+ 61 - 0
src/app/dynaform/dynaform.component.2.html

@@ -0,0 +1,61 @@
+<ng-container *ngFor="let rowName of dynaFormRows">
+	<ng-container *ngTemplateOutlet="template ? template : default; context: getTemplateContext(rowName)"></ng-container>
+</ng-container>
+
+
+<!-- Default template for form field
+		used when a TemplateRef is NOT supplied to component -->
+<ng-template let-control="control" let-meta="meta" #default>
+	<ng-container *ngIf="meta.type !== 'Hidden'">
+
+		<ng-container *ngIf="!meta.noLabel; else fullWidth">
+
+			<div class="form-group row" *ngIf="isField(meta); else recursiveDynaform" [ngClass]="getRowClass(control, meta)">
+				<label class="col-sm-4" [ngClass]="meta.class" [for]="meta.name" title="">
+					{{ meta.rowLabel ? meta.rowLabel : meta.label }}
+					<span *ngIf="control && control.touched && control.invalid" class="fas fa-exclamation-triangle"
+						[ngbTooltip]="getValidationFailureMessage(control, meta)"
+					></span>
+				</label>
+				<div class="col-sm-8">
+					<ng-container dynafield [control]="control" [meta]="meta" (call)="handleCallback($event)"></ng-container>
+				</div>
+			</div>
+			
+			<ng-template *ngIf="!isRepeatingContainer(meta) ; else recursiveDynaformArray" #recursiveDynaform>
+				<div *ngIf="meta.label" class="row">
+					<h3 class="col-sm-12 h-dyna" [ngClass]="'h-dyna-' + (path.length + 2)">{{ meta.label }}</h3>
+				</div>
+				<app-dynaform [formGroup]="control" [meta]="meta.meta" [template]="template" (call)="handleCallback($event)"></app-dynaform>
+			</ng-template>
+
+			<ng-template #recursiveDynaformArray>
+				<div *ngFor="let container of meta.meta" style="border: 1px red solid;">
+					{{ container | json }}
+					<app-dynaform [formGroup]="control" [meta]="container.meta" [template]="template" (call)="handleCallback($event)"></app-dynaform>
+				</div>
+			</ng-template>
+
+		</ng-container>
+
+		<ng-template #fullWidth>
+			<div class="row" [ngClass]="getRowClass(control, meta.type)">
+				<ng-container dynafield [control]="control" [meta]="meta" (call)="handleCallback($event)"></ng-container>
+			</div>
+		</ng-template>
+		
+	</ng-container>
+</ng-template>
+
+
+<!-- Display validation status if debugging and not nested -->
+<div *ngIf="debug && path.length === 0">
+	<pre [ngClass]="{
+			'alert-success' 	: formGroup.valid && formGroup.dirty,
+			'alert-danger' 		: !formGroup.valid && formGroup.dirty,
+			'alert-secondary' 	: !formGroup.dirty
+		}"
+		class="alert mt-4"
+		role="alert">{{ formGroup.pristine ? 'Untouched' : getValidationErrors() | json }}</pre>
+</div>
+	

+ 18 - 14
src/app/dynaform/dynaform.component.html

@@ -9,7 +9,6 @@
 	<ng-container *ngIf="meta.type !== 'Hidden'">
 
 		<ng-container *ngIf="!meta.noLabel; else fullWidth">
-
 			<div class="form-group row" *ngIf="isField(meta); else recursiveDynaform" [ngClass]="getRowClass(control, meta)">
 				<label class="col-sm-4" [ngClass]="meta.class" [for]="meta.name" title="">
 					{{ meta.rowLabel ? meta.rowLabel : meta.label }}
@@ -21,22 +20,19 @@
 					<ng-container dynafield [control]="control" [meta]="meta" (call)="handleCallback($event)"></ng-container>
 				</div>
 			</div>
-			
-			<ng-template *ngIf="!isRepeatingContainer(meta) ; else recursiveDynaformArray" #recursiveDynaform>
-				<div *ngIf="meta.label" class="row">
-					<h3 class="col-sm-12 h-dyna" [ngClass]="'h-dyna-' + (path.length + 2)">{{ meta.label }}</h3>
-				</div>
-				<app-dynaform [formGroup]="control" [meta]="meta.meta" [template]="template" (call)="handleCallback($event)"></app-dynaform>
-			</ng-template>
+		</ng-container>
 
-			<ng-template #recursiveDynaformArray>
-				<div *ngFor="let container of meta.meta" style="border: 1px red solid;">
-					{{ container | json }}
-					<app-dynaform [formGroup]="control" [meta]="container.meta" [template]="template" (call)="handleCallback($event)"></app-dynaform>
+		<ng-template #recursiveDynaform>
+			<ng-container *ngIf="isRepeatingContainer(meta); else container">
+				<div *ngFor="let container of meta.meta; let i = index">
+					<ng-container *ngTemplateOutlet="dynaform; context: getRCTemplateContext(meta.name, i)"></ng-container>
 				</div>
-			</ng-template>
+			</ng-container>
+		</ng-template>
 
-		</ng-container>
+		<ng-template #container>
+			<ng-container *ngTemplateOutlet="dynaform; context: { control: control, meta: meta }"></ng-container>
+		</ng-template>
 
 		<ng-template #fullWidth>
 			<div class="row" [ngClass]="getRowClass(control, meta.type)">
@@ -48,6 +44,14 @@
 </ng-template>
 
 
+<ng-template let-control="control" let-meta="meta" #dynaform>
+	<div *ngIf="meta.label" class="row">
+		<h3 class="col-sm-12 h-dyna" [ngClass]="'h-dyna-' + (path.length + 2)">{{ meta.label }}</h3>
+	</div>
+	<app-dynaform [formGroup]="control" [meta]="meta.meta" [template]="template" (call)="handleCallback($event)"></app-dynaform>
+</ng-template>
+
+
 <!-- Display validation status if debugging and not nested -->
 <div *ngIf="debug && path.length === 0">
 	<pre [ngClass]="{

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

@@ -1,5 +1,5 @@
 import { Component, Input, Output, EventEmitter, TemplateRef, Optional, OnInit, ChangeDetectionStrategy } from '@angular/core';
-import { FormControl, FormGroup, FormGroupName, AbstractControl, ControlContainer } from '@angular/forms';
+import { FormControl, FormGroup, FormArray, FormGroupName, AbstractControl, ControlContainer } from '@angular/forms';
 import { SuperForm } from 'angular-super-validator';
 
 export interface DynarowContext {
@@ -130,16 +130,19 @@ export class DynaformComponent implements OnInit {
 		};
 	}
 
+	getRCTemplateContext(repeatingContainerName, index): DynarowContext {
+		const repeatingContainerFormArray = this.formGroup.get(repeatingContainerName) as FormArray;
+		const result = {
+			control: repeatingContainerFormArray.at(index),
+			meta: this.formMetaData[repeatingContainerName]['meta'][index]
+		};
+		return result;
+	}
+
 	isField(meta: StringMap): boolean {
-		console.log(meta.name, meta.type);
 		return !meta.type.includes('Container');
 	}
 	
-	isContainer(meta: StringMap): boolean {
-		console.log(meta);
-		return meta.type === 'Container';
-	}
-
 	isRepeatingContainer(meta: StringMap): boolean {
 		return meta.type === 'RepeatingContainer';
 	}

+ 7 - 14
src/app/dynaform/services/_formdata-utils.ts

@@ -156,7 +156,7 @@ const resolveType = (metaFoG: StringMap): string => {
 	if (isRepeatingContainer(metaFoG)) {
 		return 'repeatingContainer';
 	}
-	return '';
+	return 'text';
 }
 
 const buildFieldClassName = (t: string): string => {
@@ -168,7 +168,7 @@ const buildFieldClassName = (t: string): string => {
 };
 
 const buildModeledField = metaFoG => {
-	const type = resolveType(metaFoG) || 'text';
+	const type = resolveType(metaFoG);
 	const className = buildFieldClassName(type);
 	if (!fmdModels[className]) {
 		throw new Error(`No metadata model "${className}" for type "${type}"`);
@@ -180,7 +180,9 @@ const buildModeledField = metaFoG => {
 const buildModeledFieldGroupMember = metaFoG => {
 	const modeledGroupMember = buildModeledField(metaFoG);
 	if (isContainer(metaFoG)) {
-		modeledGroupMember.meta = _buildFieldSpecificMeta(metaFoG.meta);
+		modeledGroupMember.meta = _buildFieldSpecificMeta(modeledGroupMember.meta);
+	} else if (isRepeatingContainer(metaFoG)) {
+		modeledGroupMember.meta = modeledGroupMember.meta.map(rcMem => ({ ...rcMem, meta: _buildFieldSpecificMeta(rcMem.meta) }));
 	}
 	return modeledGroupMember;
 };
@@ -192,8 +194,6 @@ const _buildFieldSpecificMeta = metaG => isRepeatingContainer(metaG) ?
 	reduce(buildModeledFieldGroupReducerIteree, {}, metaG);
 const buildFieldSpecificMeta = metaG => {
 	const withNames = addMissingNames(metaG);
-	console.log(metaG);
-	console.log(withNames);
 	return _buildFieldSpecificMeta(addMissingNames(metaG));
 }
 
@@ -344,7 +344,7 @@ const buildFormGroupFunctionFactory = (fb: FormBuilder): (meta) => FormGroup =>
 	// Build Form Array containing either Form Controls or Form Groups
 	const buildFormArray = (metaG): FormArray => {
 		return fb.array(
-			metaG.map(m => isRepeatingContainerMember(m) ? _buildFormGroup(m) : buildFormControl(m))
+			metaG.map(m => isContainer(m) ? _buildFormGroup(m.meta) : buildFormControl(m))
 		);
 	};
 
@@ -502,20 +502,13 @@ const isRepeatingContainer = (metaFoG): boolean => isGroup(metaFoG)
 	&& Array.isArray(metaFoG.meta)
 	&& (!metaFoG.type || metaFoG.type.toLowerCase() === 'repeatingContainer');
 
-// Is Repeating Container Member THIS IS WRONG WRONG WRIONG!!!! <-------------------------------------------------------
-const isRepeatingContainerMember = (possibleRcMem): boolean => {
-	console.log(possibleRcMem.value);
-	return possibleRcMem.value === undefined && possibleRcMem.meta === undefined;
-}
-
 // Add Missing Names
 // Helper function to add any missing 'name' properties to Fields and Groups using property's key, recursively
 // BUT not to repeatingContainer members
-// const addNameIfMissing = (metaFoG, key) => metaFoG.name || isRepeatingContainerMember(metaFoG) ? metaFoG : addProp(metaFoG, 'name', key);
 const addNameIfMissing = (metaFoG, key) => metaFoG.name ? metaFoG : addProp(metaFoG, 'name', key);
 const addNameToSelfAndChildren = ( [key, metaFoG] ) => {
 	metaFoG = addNameIfMissing(metaFoG, key);
-	if (isGroup(metaFoG)) {
+	if (isGroup(metaFoG) && !isRepeatingContainer(metaFoG)) {
 		metaFoG.meta = isArray(metaFoG.meta) ? Object.values(addMissingNames(metaFoG.meta)) : addMissingNames(metaFoG.meta); // Recursion
 	}
 	return [key, metaFoG];