123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- import { Component, Input, Output, EventEmitter, TemplateRef, Optional, OnInit, ChangeDetectionStrategy } from '@angular/core';
- import { FormControl, FormGroup, FormArray, FormGroupName, AbstractControl, ControlContainer } from '@angular/forms';
- import { SuperForm } from 'angular-super-validator';
- import { createMeta } from '@angular/platform-browser/src/browser/meta';
- export interface DynarowContext {
- control: AbstractControl;
- meta: StringMap;
- }
- @Component({
- selector: 'app-dynaform',
- templateUrl: './dynaform.component.html',
- styleUrls: ['./dynaform.component.scss'],
- changeDetection: ChangeDetectionStrategy.OnPush
- })
- export class DynaformComponent implements OnInit {
-
- @Input()
- formGroup?: FormGroup;
- @Input()
- formGroupName?: FormGroupName;
- @Input()
- set meta(data) {
- this.formMetaData = this.formMetaData || data;
- }
- @Input()
- template?: TemplateRef<any>;
- @Input()
- debug = false;
- @Output()
- call: EventEmitter<string> = new EventEmitter<string>();
- formMetaData: StringMap;
- controlNames: string[];
- dynaFormRows: string[];
- path: string[];
-
- conRed = 'color: white; background-color: maroon; font-weight: bold;';
- conGreen = 'color: white; background-color: green; font-weight: bold;';
- constructor(
- @Optional() private cc: ControlContainer,
- ) {}
- ngOnInit() {
-
- if (!this.formGroup && this.formGroupName) {
- this.formGroup = this.cc.control as FormGroup;
- }
- if (!this.formGroup) {
- throw new Error('Dynaform Component initialised without [formGroup] or formGroupName');
- }
- if (typeof this.formMetaData !== 'object') {
- throw new Error('Dynaform: [meta] should be an object');
- }
- this.controlNames = Object.keys(this.formGroup.controls);
- this.path = this.getFormGroupPath();
- if (this.debug && this.path.length < 2) {
- this.displayDebuggingInConsole();
- }
-
-
- const path = [...this.path];
- const metaDataKeysExpected = this.controlNames.join(',');
- while (path.length && metaDataKeysExpected !== this.getContolKeysCSVFromMetadata(this.formMetaData)) {
- const branch = path.pop();
- this.formMetaData = this.formMetaData[branch].meta;
- }
- this.dynaFormRows = Object.keys(this.formMetaData);
-
- const metaDataKeysFound = this.getContolKeysCSVFromMetadata(this.formMetaData);
- if (metaDataKeysFound !== metaDataKeysExpected) {
- throw new Error(`
- Dynaform can't match FormGroup's controls with metadata
- Expected ${metaDataKeysExpected}
- Got ${metaDataKeysFound}`
- );
- }
- }
- getFormGroupPath(): string[] {
-
- let path = [];
- if (!this.formGroup && this.formGroupName) {
-
- path = this.cc.path.reverse();
- } else {
-
- let fg = this.formGroup;
- while (fg.parent) {
-
- const fgIdentity = Object.entries(fg.parent.controls).find(([key, candidate]) => candidate === fg);
- path.push(fgIdentity[0]);
- fg = fg.parent as FormGroup;
- }
- }
- return path;
- }
- isField(meta: StringMap): boolean {
- return !meta.type.includes('Container');
- }
-
- isRepeatingContainer(meta: StringMap): boolean {
- return meta.type === 'RepeatingContainer';
- }
- getTemplateContext(controlName: string): DynarowContext {
- return {
- control: this.formGroup.get(controlName),
- meta: this.formMetaData[controlName]
- };
- }
- getRCTemplateContext(repeatingContainerName: string, index: number): DynarowContext {
- const repeatingContainerFormArray = this.formGroup.get(repeatingContainerName) as FormArray;
- const result = {
- control: repeatingContainerFormArray.at(index),
- meta: this.formMetaData[repeatingContainerName]['meta'][index]
- };
- return result;
- }
- getRowClass(control: FormControl, meta: StringMap): string {
- const fieldTypeClass = meta.type ? meta.type.toLowerCase().replace('component', '') : '';
- const fieldClass = Array.isArray(meta.class) ? meta.class.join(' ') : meta.class;
- const containerClass = fieldClass ? ` container-${fieldClass}` : '';
- const errorClass = control && control.touched && control.invalid ? ' dyna-error' : '';
- return `row-${fieldTypeClass}${containerClass}${errorClass}`;
- }
- getRCLabel(repeatingContainerName: string, index: number): string {
-
-
- const rcMeta = this.formMetaData[repeatingContainerName];
- const primaryField = rcMeta.primaryField;
- if (primaryField) {
-
- const repeatingContainerFormArray = this.formGroup.get(repeatingContainerName) as FormArray;
- const formGroup = repeatingContainerFormArray.at(index);
- return formGroup.get(primaryField).value;
- } else {
-
- return rcMeta.meta[index].button;
- }
- }
- focusContainer(repeatingContainerName: string, index: number): void {
-
- const rcMeta = this.formMetaData[repeatingContainerName];
- rcMeta.meta = rcMeta.meta.map( (container, i) => ({ ...container, focussed: i === index }) );
- }
- getValidationFailureMessage(control: FormControl, meta: StringMap) {
- if (control.errors) {
- const errKeys = Object.keys(control.errors);
- console.log(errKeys);
- return meta.valFailureMessages[errKeys[0]];
- }
- }
- getValidationErrors() {
- if (!this.formGroup.valid) {
- const errorsFlat = SuperForm.getAllErrorsFlat(this.formGroup);
- return errorsFlat;
- }
- return 'No Errors';
- }
- handleCallback(fnId: string) {
- this.call.emit(fnId);
- }
- private getContolKeysCSVFromMetadata(metadata): string {
-
-
-
-
- return Object.entries(metadata)
- .filter(([key, val]) => !(val as StringMap).noFormControls)
- .reduce((acc, [key]) => [...acc, key], [])
- .join(',');
- }
- private displayDebuggingInConsole(): void {
- if (this.debug) {
- console.log('%c *** MetaData *** ', this.conGreen);
- console.dir(this.formMetaData);
- console.log('%c *** FormGroup *** ', this.conGreen);
- console.dir(this.formGroup);
- }
- }
- }
|