|
@@ -1,13 +1,17 @@
|
|
|
-import { ComponentFactoryResolver, ComponentRef, Directive, Input, OnChanges, OnInit, Type, ViewContainerRef } from '@angular/core';
|
|
|
-import { FormControl } from '@angular/forms';
|
|
|
+import {
|
|
|
+ Directive, ComponentFactoryResolver, ComponentRef, ViewContainerRef,
|
|
|
+ Input, Output, EventEmitter, OnInit
|
|
|
+ SkipSelf
|
|
|
+} from '@angular/core';
|
|
|
+import { FormControl, ControlContainer, NgControl, ValidatorFn, AsyncValidatorFn } from '@angular/forms';
|
|
|
|
|
|
import * as formFieldComponents from './../components/fields';
|
|
|
|
|
|
@Directive({
|
|
|
// tslint:disable-next-line:directive-selector
|
|
|
- selector: '[dynafield]'
|
|
|
+ selector: '[dynafield]',
|
|
|
})
|
|
|
-export class DynafieldDirective implements OnInit, OnChanges {
|
|
|
+export class DynafieldDirective extends NgControl implements OnInit /* OnChanges */ {
|
|
|
|
|
|
@Input()
|
|
|
control: FormControl;
|
|
@@ -15,12 +19,20 @@ export class DynafieldDirective implements OnInit, OnChanges {
|
|
|
@Input()
|
|
|
meta: StringMap;
|
|
|
|
|
|
+ @Output('ngModelChange')
|
|
|
+ update = new EventEmitter();
|
|
|
+
|
|
|
component: ComponentRef<any>; // TODO: Tighten up on 'any'
|
|
|
|
|
|
+ _control: FormControl;
|
|
|
+
|
|
|
constructor(
|
|
|
private resolver: ComponentFactoryResolver,
|
|
|
- private container: ViewContainerRef
|
|
|
- ) {}
|
|
|
+ private container: ViewContainerRef,
|
|
|
+ @SkipSelf() private cc: ControlContainer
|
|
|
+ ) {
|
|
|
+ super();
|
|
|
+ }
|
|
|
|
|
|
ngOnInit() {
|
|
|
const type = `${this.meta.type}Component`;
|
|
@@ -31,21 +43,50 @@ export class DynafieldDirective implements OnInit, OnChanges {
|
|
|
Supported types: ${validComponentTypes}`
|
|
|
);
|
|
|
}
|
|
|
- const component = this.resolver.resolveComponentFactory<any>(formFieldComponents[type]);
|
|
|
- this.component = this.container.createComponent(component);
|
|
|
- this.component.instance.control = this.control;
|
|
|
- this.component.instance.meta = this.meta;
|
|
|
-
|
|
|
- // Now move meta variables up a level, for direct access in templates implementing dynaField
|
|
|
- Object.keys(this.meta).map(p => this[p] = this.meta[p]);
|
|
|
+ try {
|
|
|
+ this.name = this.meta.name;
|
|
|
+ const component = this.resolver.resolveComponentFactory<any>(formFieldComponents[type]);
|
|
|
+ this.component = this.container.createComponent(component);
|
|
|
+ this.component.instance.control = this.control;
|
|
|
+ this.component.instance.meta = this.meta;
|
|
|
+ if (this.component.instance.propagateChange) {
|
|
|
+ // We're dealing with a custom form control that implements the ControlValueAccessor interface,
|
|
|
+ // so we need to wire it up
|
|
|
+ this.valueAccessor = this.component.instance;
|
|
|
+ this._control = this.formDirective.addControl(this);
|
|
|
+ }
|
|
|
+ } catch(e) {
|
|
|
+ console.error('ERROR INSTANTIATING DYNAFORM FIELD COMPONENT')
|
|
|
+ console.log(e);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
ngOnChanges() {
|
|
|
if (this.component) {
|
|
|
this.component.instance.meta = this.meta;
|
|
|
this.component.instance.control = this.control;
|
|
|
}
|
|
|
}
|
|
|
+ */
|
|
|
+
|
|
|
+ get path(): string[] {
|
|
|
+ return [...this.cc.path !, this.name];
|
|
|
+ }
|
|
|
+
|
|
|
+ get formDirective(): any {
|
|
|
+ return this.cc ? this.cc.formDirective : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // get control(): FormControl { return this._control; }
|
|
|
+
|
|
|
+ get validator(): ValidatorFn | null { return null; }
|
|
|
+
|
|
|
+ get asyncValidator(): AsyncValidatorFn { return null; }
|
|
|
+
|
|
|
+ viewToModelUpdate(newValue: any): void {
|
|
|
+ this.update.emit(newValue);
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|