angular-dynamic-forms-lite
Version:
Efficient dynamic and customizable Angular 7+ forms.
1,817 lines (1,795 loc) • 58.3 kB
JavaScript
import { Directive, ViewContainerRef, InjectionToken, EventEmitter, Injectable, ComponentFactoryResolver, Injector, Optional, Inject, ɵɵdefineInjectable, ɵɵinject, INJECTOR, Component, ChangeDetectionStrategy, ViewChild, NgModule } from '@angular/core';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { bufferCount, map, filter } from 'rxjs/operators';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class FormRootDirective {
/**
* @param {?} viewContainerRef
*/
constructor(viewContainerRef) {
this.viewContainerRef = viewContainerRef;
}
/**
* @param {?} index
* @return {?}
*/
getViewRef(index) {
return this.viewContainerRef.get(index);
}
/**
* @return {?}
*/
getViewRefs() {
/** @type {?} */
const viewRefs = [];
for (let i = 0; i < this.getSize(); i++) {
viewRefs.push(this.viewContainerRef.get(i));
}
return viewRefs;
}
/**
* @param {?} viewRef
* @return {?}
*/
containsViewRef(viewRef) {
return this.viewContainerRef.indexOf(viewRef) !== -1;
}
/**
* @return {?}
*/
getSize() {
return this.viewContainerRef.length;
}
/**
* @return {?}
*/
clearView() {
this.viewContainerRef.clear();
}
}
FormRootDirective.decorators = [
{ type: Directive, args: [{
selector: "[form-root], form-root"
},] }
];
/** @nocollapse */
FormRootDirective.ctorParameters = () => [
{ type: ViewContainerRef }
];
if (false) {
/** @type {?} */
FormRootDirective.prototype.viewContainerRef;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const FIELD_METADATA = new InjectionToken("metadata");
/** @type {?} */
const FIELD_FORM_CONTROL = new InjectionToken("form control");
/** @type {?} */
const FIELD_DYNAMIC_CONTROLLER = new InjectionToken("dynamic controller");
/** @type {?} */
const FIELD_NAME = new InjectionToken("form field name");
class FormFieldInjector {
/**
* @param {?} _parentInjector
* @param {?} _additionalTokens
*/
constructor(_parentInjector, _additionalTokens) {
this._parentInjector = _parentInjector;
this._additionalTokens = _additionalTokens;
}
/**
* @param {?} token
* @param {?=} notFoundValue
* @param {?=} flags
* @return {?}
*/
get(token, notFoundValue, flags) {
/** @type {?} */
const value = this._additionalTokens.get(token);
return value !== undefined ? value : this._parentInjector.get(token, notFoundValue, flags);
}
}
if (false) {
/**
* @type {?}
* @private
*/
FormFieldInjector.prototype._parentInjector;
/**
* @type {?}
* @private
*/
FormFieldInjector.prototype._additionalTokens;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const DEFAULT_SUB_TYPE = "DEFAULT";
/** @enum {string} */
const DynamicFormType = {
/**
* Number form type
*/
GROUP: "GROUP",
/**
* Array form type
*/
ARRAY: "ARRAY",
/**
* Single form type
*/
SINGLE: "SINGLE",
/**
* Hidden form type
*/
HIDDEN: "HIDDEN",
};
/**
* @param {?} value
* @return {?}
*/
function isDynamicFieldType(value) {
return value in DynamicFormType;
}
/** @type {?} */
const DEFAULT_FORM_COMPONENTS = new InjectionToken("default form components");
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Describes a form field using its type and sub type.
*/
class SubType {
/**
* @param {?=} type
* @param {?=} subType
*/
constructor(type = DynamicFormType.SINGLE, subType = DEFAULT_SUB_TYPE) {
this.type = type;
this.subType = subType;
}
/**
* @param {?} type
* @param {?=} subType
* @return {?}
*/
static of(type, subType) {
return new SubType(type, subType);
}
/**
* @param {?} fieldType
* @return {?}
*/
static toSubType(fieldType) {
return fieldType instanceof SubType ? fieldType : SubType.of(fieldType);
}
}
if (false) {
/** @type {?} */
SubType.prototype.type;
/** @type {?} */
SubType.prototype.subType;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @record
* @template M, T, S
*/
function CreateFormContextOptions() { }
if (false) {
/** @type {?|undefined} */
CreateFormContextOptions.prototype.initialValue;
/** @type {?|undefined} */
CreateFormContextOptions.prototype.formControl;
/** @type {?} */
CreateFormContextOptions.prototype.setting;
/** @type {?} */
CreateFormContextOptions.prototype.settings;
}
/**
* @record
* @template T, S
*/
function FieldFactory() { }
if (false) {
/**
* @template M
* @param {?} params
* @return {?}
*/
FieldFactory.prototype.create = function (params) { };
/**
* @param {?} formRoot
* @param {?} root
* @return {?}
*/
FieldFactory.prototype.render = function (formRoot, root) { };
/**
* @param {?} context
* @return {?}
*/
FieldFactory.prototype.updateChildren = function (context) { };
}
class ParentFieldFactory {
/**
* @param {?} factories
* @param {?} componentFactoryResolver
* @param {?} injector
* @param {?} formBuilder
* @param {?} settings
*/
constructor(factories, componentFactoryResolver, injector, formBuilder, settings) {
this.factories = factories;
this.componentFactoryResolver = componentFactoryResolver;
this.injector = injector;
this.formBuilder = formBuilder;
this.settings = settings;
}
/**
* @template M
* @param {?} params
* @return {?}
*/
create(params) {
return this.getFactory(params.setting).create(params);
}
/**
* @param {?} formRoot
* @param {?} root
* @return {?}
*/
render(formRoot, root) {
return this.getFactory(root.setting).render(formRoot, root);
}
/**
* @param {?} context
* @return {?}
*/
updateChildren(context) {
return this.getFactory(context.setting).updateChildren(context);
}
/**
* @template M, H
* @param {?} formControl
* @param {?} setting
* @param {?} value
* @param {?} dynamicController
* @return {?}
*/
resolveComponent(formControl, setting, value, dynamicController) {
/** @type {?} */
let componentFactory;
try {
componentFactory = this.componentFactoryResolver.resolveComponentFactory(setting.component);
}
catch (e) {
console.error(`Cannot resolve component factory for ${setting.name}. ${setting.component ? "" : "Component is undefined."}`);
throw e;
}
/** @type {?} */
const additionalTokens = new WeakMap();
additionalTokens.set(FIELD_METADATA, setting.metadata || {});
additionalTokens.set(FIELD_FORM_CONTROL, formControl);
additionalTokens.set(FIELD_DYNAMIC_CONTROLLER, dynamicController);
additionalTokens.set(FIELD_NAME, setting.name);
/** @type {?} */
const dynamicInjector = new FormFieldInjector(this.injector, additionalTokens);
/** @type {?} */
const componentRef = componentFactory.create(dynamicInjector);
dynamicController.componentRef = componentRef;
this.patchAsyncChangeDetection(formControl, componentRef.changeDetectorRef);
return (/** @type {?} */ ({
initialValue: value,
formControl,
setting,
settings: this.settings,
componentRef,
children: []
}));
}
/**
* @private
* @param {?} formControl
* @param {?} cdr
* @return {?}
*/
patchAsyncChangeDetection(formControl, cdr) {
formControl.statusChanges
.pipe(bufferCount(2, 1), map((/**
* @param {?} __0
* @return {?}
*/
([prevState]) => prevState)), filter((/**
* @param {?} prevState
* @return {?}
*/
prevState => prevState === "PENDING")))
.subscribe((/**
* @return {?}
*/
() => cdr.markForCheck()));
}
/**
* @private
* @template M
* @param {?} setting
* @return {?}
*/
getFactory(setting) {
/** @type {?} */
const factoryType = SubType.toSubType(setting.type).type;
/** @type {?} */
const factory = this.factories[factoryType];
if (!factory) {
throw new Error(`Field factory ${factoryType} does not exist.`);
}
return new factory(this, this.formBuilder);
}
}
if (false) {
/**
* @type {?}
* @private
*/
ParentFieldFactory.prototype.factories;
/**
* @type {?}
* @private
*/
ParentFieldFactory.prototype.componentFactoryResolver;
/**
* @type {?}
* @private
*/
ParentFieldFactory.prototype.injector;
/**
* @type {?}
* @private
*/
ParentFieldFactory.prototype.formBuilder;
/**
* @type {?}
* @private
*/
ParentFieldFactory.prototype.settings;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @abstract
*/
class DynamicController {
/**
* @param {?} _componentRef
* @return {?}
*/
set componentRef(_componentRef) {
this._componentRef = _componentRef;
}
}
if (false) {
/**
* @type {?}
* @protected
*/
DynamicController.prototype._componentRef;
/**
* @abstract
* @param {?} context
* @return {?}
*/
DynamicController.prototype.onInit = function (context) { };
/**
* @abstract
* @protected
* @return {?}
*/
DynamicController.prototype.destory = function () { };
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @template M
*/
class DynamicGroupController extends DynamicController {
/**
* @param {?} formGroup
* @param {?} fieldFactory
* @param {?} setting
* @param {?} settings
*/
constructor(formGroup, fieldFactory, setting, settings) {
super();
this.formGroup = formGroup;
this.fieldFactory = fieldFactory;
this.setting = setting;
this.settings = settings;
}
/**
* @param {?} context
* @return {?}
*/
onInit(context) { }
/**
* @protected
* @return {?}
*/
destory() {
// TODO
}
}
if (false) {
/**
* @type {?}
* @private
*/
DynamicGroupController.prototype.formGroup;
/**
* @type {?}
* @private
*/
DynamicGroupController.prototype.fieldFactory;
/**
* @type {?}
* @private
*/
DynamicGroupController.prototype.setting;
/**
* @type {?}
* @private
*/
DynamicGroupController.prototype.settings;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class GroupFieldFactory {
/**
* @param {?} parentFieldFactory
* @param {?} formBuilder
*/
constructor(parentFieldFactory, formBuilder) {
this.parentFieldFactory = parentFieldFactory;
this.formBuilder = formBuilder;
}
/**
* @template M
* @param {?} options
* @return {?}
*/
create(options) {
const { setting, settings } = options;
const [formControl, children] = this.createChildContexts(options);
/** @type {?} */
const dynamicController = new DynamicGroupController(formControl, this.parentFieldFactory, setting, settings);
/** @type {?} */
const groupFormContext = Object.assign({}, this.parentFieldFactory.resolveComponent(formControl, setting, options.initialValue, dynamicController), { children });
/** @type {?} */
const groupComponent = (/** @type {?} */ (groupFormContext.componentRef.instance));
if (!groupComponent.formRoot) {
throw new Error(`Group component ${setting.name} is not a group component. It is missing the 'formRoot' directive.`);
}
dynamicController.onInit(groupFormContext);
return groupFormContext;
}
/**
* @param {?} formRoot
* @param {?} root
* @return {?}
*/
render(formRoot, root) {
/** @type {?} */
const viewRef = formRoot.viewContainerRef.insert(root.componentRef.hostView);
viewRef.detectChanges();
/** @type {?} */
const entries = Object.entries(root.children);
entries.forEach((/**
* @param {?} __0
* @return {?}
*/
([_id, context]) => {
/** @type {?} */
const component = (/** @type {?} */ (root.componentRef.instance));
this.parentFieldFactory.render(component.formRoot, context);
}));
return viewRef;
}
/**
* @param {?} context
* @return {?}
*/
updateChildren(context) {
/** @type {?} */
const controlEntires = Object.entries(context.formControl.controls);
/** @type {?} */
const entries = Object.entries(context.children);
entries.forEach((/**
* @param {?} __0
* @return {?}
*/
([_id, child]) => {
/** @type {?} */
const missingFormControl = controlEntires.find((/**
* @param {?} entry
* @return {?}
*/
entry => child.formControl === entry[1]));
if (missingFormControl) {
context.formControl.setControl(missingFormControl[0], missingFormControl[1]);
}
}));
}
/**
* @private
* @template M
* @param {?} options
* @return {?}
*/
createChildContexts(options) {
const { setting, settings } = options;
if (options.formControl) {
/** @type {?} */
const controlEntires = Object.entries(options.formControl.controls);
/** @type {?} */
const children = {};
controlEntires.forEach((/**
* @param {?} __0
* @return {?}
*/
([id, formControl]) => {
children[id] = this.parentFieldFactory.create({
formControl,
setting: this.getSetting(id, settings),
settings
});
}));
return [options.formControl, children];
}
const { initialValue: value } = options;
if (typeof value !== "object") {
throw new Error(`Value of group ${setting.name} is not an object`);
}
/** @type {?} */
const children = {};
/** @type {?} */
const formChildren = {};
Object.entries(value).forEach((/**
* @param {?} __0
* @return {?}
*/
([id, child]) => {
children[id] = this.parentFieldFactory.create({
initialValue: child,
setting: this.getSetting(id, settings),
settings
});
formChildren[id] = children[id].formControl;
}));
/** @type {?} */
const formControl = this.formBuilder.group(formChildren);
return [formControl, children];
}
/**
* @private
* @template M
* @param {?} id
* @param {?} settings
* @return {?}
*/
getSetting(id, settings) {
/** @type {?} */
const childSetting = (/** @type {?} */ (settings.get(id)));
if (!childSetting) {
throw new Error(`Form field '${id}' has no assigned form field setting.`);
}
return childSetting;
}
}
if (false) {
/**
* @type {?}
* @private
*/
GroupFieldFactory.prototype.parentFieldFactory;
/**
* @type {?}
* @private
*/
GroupFieldFactory.prototype.formBuilder;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class ArrayRenderer {
// TODO is arrayRoot needed
/**
* @param {?} parentFieldFactory
* @param {?} arrayRoot
*/
constructor(parentFieldFactory, arrayRoot) {
this.parentFieldFactory = parentFieldFactory;
this.arrayRoot = arrayRoot;
}
/**
* @param {?} context
* @param {?} pageEvent
* @return {?}
*/
render(context, pageEvent) {
this.renderChildren(this.arrayRoot, this.getChildrenToRender((/** @type {?} */ (context.children)), pageEvent));
}
/**
* @private
* @param {?} arrayRoot
* @param {?} contexts
* @return {?}
*/
renderChildren(arrayRoot, contexts) {
arrayRoot.clearView();
contexts.forEach((/**
* @param {?} context
* @return {?}
*/
context => {
if (context.componentRef.hostView.destroyed) {
// recreate the view if it is destroyed
/** @type {?} */
const newContext = this.parentFieldFactory.create(context);
this.parentFieldFactory.render(arrayRoot, newContext);
return;
}
this.parentFieldFactory.render(arrayRoot, context);
}));
}
/**
* @private
* @param {?} children
* @param {?} pageEvent
* @return {?}
*/
getChildrenToRender(children, pageEvent) {
return children.slice(pageEvent.pageIndex * pageEvent.pageSize, (pageEvent.pageIndex + 1) * pageEvent.pageSize);
}
}
if (false) {
/**
* @type {?}
* @private
*/
ArrayRenderer.prototype.parentFieldFactory;
/**
* @type {?}
* @private
*/
ArrayRenderer.prototype.arrayRoot;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @template M, CM
*/
class DynamicArrayController extends DynamicController {
/**
* @param {?} parentFieldFactory
*/
constructor(parentFieldFactory) {
super();
this.parentFieldFactory = parentFieldFactory;
this.subscriptions = [];
}
/**
* @param {?} context
* @return {?}
*/
onInit(context) {
this.arrayContext = context;
this.renderer = new ArrayRenderer(this.parentFieldFactory, this.arrayRoot);
this.paginator.updateTotalSize(this.children.length);
this.subscriptions.push(this.paginator.onPageEvent().subscribe((/**
* @param {?} event
* @return {?}
*/
event => this.renderPage(event))));
}
/**
* @return {?}
*/
get paginator() {
return this.setting.renderStrategy.paginator;
}
/**
* @private
* @return {?}
*/
get children() {
return (/** @type {?} */ (this.arrayContext.children));
}
/**
* @private
* @return {?}
*/
get formArray() {
return this.arrayContext.formControl;
}
/**
* @private
* @return {?}
*/
get setting() {
return (/** @type {?} */ (this.arrayContext.setting));
}
/**
* @private
* @return {?}
*/
get settings() {
return this.arrayContext.settings;
}
/**
* @param {?} value
* @return {?}
*/
push(value) {
/** @type {?} */
const newChildContext = this.parentFieldFactory.create({
setting: this.setting.childSetting,
settings: this.settings,
initialValue: value
});
this.children.push(newChildContext);
this.parentFieldFactory.updateChildren(this.arrayContext);
this.paginator.updateTotalSize(this.children.length);
this.renderPage();
}
/**
* @param {?} index
* @return {?}
*/
removeAt(index) {
if (index >= this.children.length || index < 0) {
return false;
}
this.children.splice(index, 1);
this.parentFieldFactory.updateChildren(this.arrayContext);
this.paginator.updateTotalSize(this.children.length);
this.renderPage();
return true;
}
/**
* @protected
* @return {?}
*/
destory() {
this.subscriptions.forEach((/**
* @param {?} s
* @return {?}
*/
s => s.unsubscribe()));
}
/**
* @private
* @param {?=} pageEvent
* @return {?}
*/
renderPage(pageEvent = this.paginator.currentPage) {
return this.renderer.render(this.arrayContext, pageEvent);
}
/**
* @private
* @return {?}
*/
get arrayRoot() {
return ((/** @type {?} */ (this._componentRef.instance))).formRoot;
}
}
if (false) {
/**
* @type {?}
* @private
*/
DynamicArrayController.prototype.arrayContext;
/**
* @type {?}
* @private
*/
DynamicArrayController.prototype.subscriptions;
/**
* @type {?}
* @private
*/
DynamicArrayController.prototype.renderer;
/**
* @type {?}
* @private
*/
DynamicArrayController.prototype.parentFieldFactory;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class ArrayFieldFactory {
/**
* @param {?} parentFieldFactory
* @param {?} formBuilder
*/
constructor(parentFieldFactory, formBuilder) {
this.parentFieldFactory = parentFieldFactory;
this.formBuilder = formBuilder;
}
/**
* @template M
* @param {?} options
* @return {?}
*/
create(options) {
const { setting } = options;
if (!setting.childSetting) {
throw new Error(`Array ${options.setting.name} needs 'childSetting' as part of its setting.`);
}
const [formControl, children] = this.createChildContexts(options);
/** @type {?} */
const dynamicController = new DynamicArrayController(this.parentFieldFactory);
/** @type {?} */
const arrayComponentContext = Object.assign({}, this.parentFieldFactory.resolveComponent(formControl, setting, options.initialValue, dynamicController), { children });
/** @type {?} */
const arrayComponent = (/** @type {?} */ (arrayComponentContext.componentRef.instance));
if (!arrayComponent.formRoot) {
throw new Error(`Array component ${setting.name} is not an array component. It is missing the 'formRoot' directive.`);
}
// initialize controller after all values and children are resolved
dynamicController.onInit(arrayComponentContext);
return arrayComponentContext;
}
/**
* @param {?} arrayContext
* @return {?}
*/
updateChildren(arrayContext) {
/** @type {?} */
const unchecked = [...arrayContext.formControl.controls];
((/** @type {?} */ (arrayContext.children))).forEach((/**
* @param {?} child
* @param {?} i
* @return {?}
*/
(child, i) => {
if (arrayContext.formControl.controls.indexOf(child.formControl) === -1) {
arrayContext.formControl.insert(i, child.formControl);
}
else {
unchecked.splice(unchecked.indexOf(child.formControl), 1);
}
}));
unchecked.forEach((/**
* @param {?} control
* @return {?}
*/
control => arrayContext.formControl.removeAt(arrayContext.formControl.controls.indexOf(control))));
}
/**
* @param {?} formRoot
* @param {?} arrayContext
* @return {?}
*/
render(formRoot, arrayContext) {
/** @type {?} */
const viewRef = formRoot.viewContainerRef.insert(arrayContext.componentRef.hostView);
viewRef.detectChanges();
/** @type {?} */
const arrayComponent = (/** @type {?} */ (arrayContext.componentRef.instance));
/** @type {?} */
const paginator = ((/** @type {?} */ (arrayContext.setting))).renderStrategy.paginator;
/** @type {?} */
const pageEvent = { pageIndex: paginator.pageIndex, pageSize: paginator.pageSize };
/** @type {?} */
const renderer = new ArrayRenderer(this.parentFieldFactory, arrayComponent.formRoot);
renderer.render(arrayContext, pageEvent);
return viewRef;
}
/**
* @private
* @template M
* @param {?} options
* @return {?}
*/
createChildContexts(options) {
if (options.formControl) {
/** @type {?} */
const children = options.formControl.controls.map((/**
* @param {?} formControl
* @return {?}
*/
formControl => this.parentFieldFactory.create({
formControl,
setting: options.setting.childSetting,
settings: options.settings
})));
return [options.formControl, children];
}
/** @type {?} */
const values = options.initialValue ? options.initialValue : [];
if (!Array.isArray(values)) {
throw new Error(`Value of ${options.setting.name} is not an array.`);
}
/** @type {?} */
const children = values.map((/**
* @param {?} value
* @return {?}
*/
value => this.parentFieldFactory.create({
initialValue: value,
setting: options.setting.childSetting,
settings: options.settings
})));
/** @type {?} */
const formControl = this.formBuilder.array(children.map((/**
* @param {?} context
* @return {?}
*/
context => context.formControl)));
return [formControl, children];
}
}
if (false) {
/**
* @type {?}
* @private
*/
ArrayFieldFactory.prototype.parentFieldFactory;
/**
* @type {?}
* @private
*/
ArrayFieldFactory.prototype.formBuilder;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @template M
*/
class DynamicSingleController extends DynamicController {
/**
* @param {?} formControl
* @param {?} fieldFactory
* @param {?} setting
* @param {?} settings
*/
constructor(formControl, fieldFactory, setting, settings) {
super();
this.formControl = formControl;
this.fieldFactory = fieldFactory;
this.setting = setting;
this.settings = settings;
}
/**
* @param {?} context
* @return {?}
*/
onInit(context) { }
/**
* @protected
* @return {?}
*/
destory() {
// TODO
}
}
if (false) {
/**
* @type {?}
* @private
*/
DynamicSingleController.prototype.formControl;
/**
* @type {?}
* @private
*/
DynamicSingleController.prototype.fieldFactory;
/**
* @type {?}
* @private
*/
DynamicSingleController.prototype.setting;
/**
* @type {?}
* @private
*/
DynamicSingleController.prototype.settings;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class SingleFieldFactory {
/**
* @param {?} parentFieldFactory
* @param {?} formBuilder
*/
constructor(parentFieldFactory, formBuilder) {
this.parentFieldFactory = parentFieldFactory;
this.formBuilder = formBuilder;
}
/**
* @template M
* @param {?} __0
* @return {?}
*/
create({ initialValue: value, formControl, setting, settings }) {
if (!formControl) {
formControl = this.formBuilder.control(value);
formControl.setValidators(setting.validators ? setting.validators : []);
formControl.setAsyncValidators(setting.asyncValidators ? setting.asyncValidators : []);
}
/** @type {?} */
const dynamicController = new DynamicSingleController(formControl, this.parentFieldFactory, setting, settings);
return this.parentFieldFactory.resolveComponent(formControl, setting, value, dynamicController);
}
/**
* @param {?} formRoot
* @param {?} root
* @return {?}
*/
render(formRoot, root) {
/** @type {?} */
const viewRef = formRoot.viewContainerRef.insert(root.componentRef.hostView);
viewRef.detectChanges();
return viewRef;
}
/**
* @param {?} context
* @return {?}
*/
updateChildren(context) { }
}
if (false) {
/**
* @type {?}
* @private
*/
SingleFieldFactory.prototype.parentFieldFactory;
/**
* @type {?}
* @private
*/
SingleFieldFactory.prototype.formBuilder;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const ROOT_ID = "__ROOT__";
/**
* @param {?} rootSetting
* @param {?} settings
* @param {?} defaultFormComponents
* @return {?}
*/
function createFormFieldSettings(rootSetting, settings, defaultFormComponents) {
if (settings.has(ROOT_ID)) {
/** @type {?} */
const illegalSetting = settings.get(ROOT_ID);
throw new Error(`Illegal form field id ${illegalSetting.name} detected for ${illegalSetting.name}`);
}
/** @type {?} */
const combinedSettings = new Map();
combinedSettings.set(ROOT_ID, {
name: ROOT_ID,
component: rootSetting.component,
type: DynamicFormType.GROUP,
metadata: rootSetting.metadata
});
settings.forEach((/**
* @param {?} setting
* @param {?} id
* @return {?}
*/
(setting, id) => combinedSettings.set(id, Object.assign({}, setting, { type: setting.type ? setting.type : ((/** @type {?} */ (DynamicFormType.SINGLE))) }))));
// add missing components from default form components
for (let [, setting] of combinedSettings) {
setting.type = SubType.toSubType(setting.type);
if (setting.component || setting.type.type === DynamicFormType.HIDDEN)
continue;
setting.component = ensureDefaultFormComponents(defaultFormComponents, setting.name, setting.type);
}
return combinedSettings;
}
/**
* @param {?} defaultFormComponents
* @param {?} name
* @param {?} _type
* @return {?}
*/
function ensureDefaultFormComponents(defaultFormComponents, name, _type) {
if (!defaultFormComponents) {
throw new Error(`No default form components available, but you used a DynamicFormType as an component identifier for ${name}. Did you add the module using DynamicFormsLiteModule.withDefaultComponents()?`);
}
/** @type {?} */
const subType = SubType.toSubType(_type);
/** @type {?} */
const component = defaultFormComponents.get(subType.type)[subType.subType];
if (!component) {
throw new Error(`No default form component for type ${subType.subType} (${subType.type}) available.`);
}
return component;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @record
*/
function PageEvent() { }
if (false) {
/** @type {?} */
PageEvent.prototype.pageSize;
/** @type {?} */
PageEvent.prototype.pageIndex;
}
class Paginator {
/**
* @param {?} _pageSize
*/
constructor(_pageSize) {
this._pageSize = _pageSize;
this._pageIndex = 0;
this.totalSize = 0;
this.pageEvents = new EventEmitter();
}
/**
* @param {?} totalSize
* @return {?}
*/
updateTotalSize(totalSize) {
this.totalSize = totalSize;
/** @type {?} */
const newPageIndex = this.maxPageIndex;
if (newPageIndex < this._pageIndex) {
this._pageIndex = newPageIndex;
this.pageEvents.next(this.currentPage);
}
}
/**
* @return {?}
*/
get pageIndex() {
return this._pageIndex;
}
/**
* @return {?}
*/
get maxPageIndex() {
if (this.totalSize === 0) {
return 0;
}
return Math.ceil(this.totalSize / this._pageSize) - 1;
}
/**
* @return {?}
*/
get pageSize() {
return this._pageSize;
}
/**
* @return {?}
*/
get currentPage() {
return {
pageIndex: this._pageIndex,
pageSize: this._pageSize
};
}
/**
* @return {?}
*/
hasNextPage() {
return (this._pageIndex + 1) * this._pageSize < this.totalSize;
}
/**
* @return {?}
*/
hasPreviousPage() {
return this._pageIndex !== 0;
}
/**
* @return {?}
*/
nextPage() {
if (!this.hasNextPage())
return false;
this._pageIndex++;
this.pageEvents.next({
pageIndex: this.pageIndex,
pageSize: this.pageSize
});
return true;
}
/**
* @return {?}
*/
previousPage() {
if (!this.hasPreviousPage())
return false;
this._pageIndex--;
this.pageEvents.next({
pageIndex: this.pageIndex,
pageSize: this.pageSize
});
return true;
}
/**
* @return {?}
*/
onPageEvent() {
return this.pageEvents;
}
}
if (false) {
/**
* @type {?}
* @private
*/
Paginator.prototype._pageIndex;
/**
* @type {?}
* @private
*/
Paginator.prototype.totalSize;
/**
* @type {?}
* @private
*/
Paginator.prototype.pageEvents;
/**
* @type {?}
* @private
*/
Paginator.prototype._pageSize;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @record
*/
function ArrayRenderStrategyOptions() { }
if (false) {
/** @type {?} */
ArrayRenderStrategyOptions.prototype.pageSize;
}
class ArrayRenderStrategy {
/**
* @param {?} options
*/
constructor(options) {
this.options = options;
this._paginator = new Paginator(options.pageSize);
}
/**
* @return {?}
*/
static withFullRender() {
return new ArrayRenderStrategy({
pageSize: Infinity
});
}
/**
* @param {?} pageSize
* @return {?}
*/
static withPartialRender(pageSize) {
return new ArrayRenderStrategy({
pageSize
});
}
/**
* @return {?}
*/
get paginator() {
return this._paginator;
}
/**
* @return {?}
*/
get pageSize() {
return this.options.pageSize;
}
}
if (false) {
/**
* @type {?}
* @private
*/
ArrayRenderStrategy.prototype._paginator;
/**
* @type {?}
* @private
*/
ArrayRenderStrategy.prototype.options;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const MissingSettingResolver = (/**
* @param {?} __0
* @return {?}
*/
([setting]) => {
throw new Error(`Unssuported form field for ${setting.name}`);
});
const ɵ0 = MissingSettingResolver;
/** @type {?} */
const ComponentSettingResolver = (/**
* @param {?} __0
* @return {?}
*/
([setting, form]) => {
if (typeof form !== "function") {
return {
match: false
};
}
setting.component = form;
return {
match: true,
value: [[setting.name, (/** @type {?} */ (setting))]]
};
});
const ɵ1 = ComponentSettingResolver;
/** @type {?} */
const DynamicTypeSettingResolver = (/**
* @param {?} __0
* @param {?} componentResolver
* @return {?}
*/
([setting, form, optionalComponent], componentResolver) => {
if (!isDynamicFieldType(form) && !(form instanceof SubType)) {
return {
match: false
};
}
if (form !== DynamicFormType.HIDDEN && !(form instanceof SubType && form.type === DynamicFormType.HIDDEN)) {
setting.component = componentResolver(setting, optionalComponent);
}
setting.type = form;
return {
match: true,
value: [[setting.name, (/** @type {?} */ (setting))]]
};
});
const ɵ2 = DynamicTypeSettingResolver;
/** @type {?} */
const ArraySettingResolver = (/**
* @param {?} __0
* @param {?} componentResolver
* @param {?} factory
* @return {?}
*/
([setting, form, optionalComponent], componentResolver, factory) => {
if (!Array.isArray(form)) {
return {
match: false
};
}
setting.type = DynamicFormType.ARRAY;
setting.component = (/** @type {?} */ (componentResolver(setting, optionalComponent)));
setting.renderStrategy = setting.renderStrategy || ArrayRenderStrategy.withFullRender();
const [[, childSetting], ...indirectChildren] = factory(form);
setting.childSetting = childSetting;
return {
match: true,
value: [[setting.name, (/** @type {?} */ (setting))], ...indirectChildren]
};
});
const ɵ3 = ArraySettingResolver;
/** @type {?} */
const GroupSettingResolver = (/**
* @param {?} __0
* @param {?} componentResolver
* @param {?} factory
* @return {?}
*/
([setting, form, optionalComponent], componentResolver, factory) => {
if (typeof form !== "object") {
return {
match: false
};
}
/** @type {?} */
const children = Object.entries(form).reduce((/**
* @param {?} settings
* @param {?} __1
* @return {?}
*/
(settings, [id, options]) => {
const [[, childSetting], ...indirectChildren] = factory(options);
return [...settings, [id, childSetting], ...indirectChildren];
}), []);
// form root does not have a name
if (!setting.name) {
return {
match: true,
value: children
};
}
setting.type = DynamicFormType.GROUP;
setting.component = componentResolver(setting, optionalComponent);
return {
match: true,
value: [[setting.name, (/** @type {?} */ (setting))], ...children]
};
});
const ɵ4 = GroupSettingResolver;
class InlineSettingsResolver {
/**
* @param {?=} defaultFormComponents
*/
constructor(defaultFormComponents) {
this.defaultFormComponents = defaultFormComponents;
this.resolvers = [
DynamicTypeSettingResolver,
ComponentSettingResolver,
ArraySettingResolver,
GroupSettingResolver,
MissingSettingResolver
];
}
/**
* @param {?} inlineForm
* @return {?}
*/
resolve(inlineForm) {
return new Map(this.resolveSettings([null, inlineForm]));
}
/**
* @private
* @param {?} __0
* @return {?}
*/
resolveSettings([nameOrSetting, form, optionalComponent]) {
/** @type {?} */
let setting = this.createPartialSetting(nameOrSetting);
return this.resolvers.reduce((/**
* @param {?} prev
* @param {?} curr
* @return {?}
*/
(prev, curr) => prev.match
? prev
: curr([setting, form, optionalComponent], this.componentResolver.bind(this), this.resolveSettings.bind(this))), {
match: false,
value: []
}).value;
}
/**
* @private
* @param {?} nameOrSetting
* @return {?}
*/
createPartialSetting(nameOrSetting) {
/** @type {?} */
let setting = {};
if (typeof nameOrSetting === "string") {
setting.name = nameOrSetting;
}
else {
setting = nameOrSetting || {};
}
return setting;
}
/**
* @private
* @param {?} setting
* @param {?} optionalComponent
* @return {?}
*/
componentResolver(setting, optionalComponent) {
return optionalComponent || ensureDefaultFormComponents(this.defaultFormComponents, setting.name, setting.type);
}
}
if (false) {
/**
* @type {?}
* @private
*/
InlineSettingsResolver.prototype.resolvers;
/**
* @type {?}
* @private
*/
InlineSettingsResolver.prototype.defaultFormComponents;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const ArrayResolver = (/**
* @param {?} valueOrType
* @return {?}
*/
(valueOrType) => {
return {
match: Array.isArray(valueOrType),
value: []
};
});
const ɵ0$1 = ArrayResolver;
/** @type {?} */
const GroupResolver = (/**
* @param {?} valueOrType
* @param {?} factory
* @return {?}
*/
(valueOrType, factory) => {
if (typeof valueOrType !== "object" || valueOrType instanceof SubType) {
return {
match: false
};
}
return {
match: true,
value: Object.entries(valueOrType).reduce((/**
* @param {?} formModel
* @param {?} __1
* @return {?}
*/
(formModel, [id, options]) => (Object.assign({}, formModel, { [id]: factory(options) }))), {})
};
});
const ɵ1$1 = GroupResolver;
/**
* Given an inline form it will resolve the model. No default values are used.
*
* Note: InlineOptions might have a default value in the future
*/
class InlineModelResolver {
constructor() {
this.resolvers = [ArrayResolver, GroupResolver];
}
/**
* @param {?} inlineForm
* @return {?}
*/
resolve(inlineForm) {
return this.resolveInlineOptions([null, inlineForm]);
}
/**
* @private
* @param {?} __0
* @return {?}
*/
resolveInlineOptions([, child]) {
return (((/** @type {?} */ (this.resolvers.reduce((/**
* @param {?} prev
* @param {?} curr
* @return {?}
*/
(prev, curr) => (prev.match ? prev : curr(child, this.resolveInlineOptions.bind(this)))), {
match: false,
value: null
}).value))) || null);
}
}
if (false) {
/**
* @type {?}
* @private
*/
InlineModelResolver.prototype.resolvers;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class InlineFormFactory {
/**
* @param {?=} defaultFormComponents
*/
constructor(defaultFormComponents) {
this.inlineSettingsResolver = new InlineSettingsResolver(defaultFormComponents);
this.inlineModelResolver = new InlineModelResolver();
}
/**
* @param {?} inlineForm
* @return {?}
*/
resolveSettings(inlineForm) {
return this.inlineSettingsResolver.resolve(inlineForm);
}
/**
* @param {?} inlineForm
* @return {?}
*/
resolveModel(inlineForm) {
return this.inlineModelResolver.resolve(inlineForm);
}
}
if (false) {
/**
* @type {?}
* @private
*/
InlineFormFactory.prototype.inlineSettingsResolver;
/**
* @type {?}
* @private
*/
InlineFormFactory.prototype.inlineModelResolver;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class HiddenFieldFactory {
/**
* @param {?} parentFieldFactory
* @param {?} formBuilder
*/
constructor(parentFieldFactory, formBuilder) {
this.parentFieldFactory = parentFieldFactory;
this.formBuilder = formBuilder;
}
/**
* @template M
* @param {?} __0
* @return {?}
*/
create({ initialValue: value, formControl, setting, settings }) {
if (!formControl) {
formControl = this.formBuilder.control(value);
formControl.setValidators(setting.validators ? setting.validators : []);
formControl.setAsyncValidators(setting.asyncValidators ? setting.asyncValidators : []);
}
return (/** @type {?} */ ({
initialValue: value,
formControl,
setting,
settings,
componentRef: null,
children: []
}));
}
/**
* @return {?}
*/
render() {
// hidden fields are not rendered
return null;
}
/**
* @return {?}
*/
updateChildren() { }
}
if (false) {
/**
* @type {?}
* @private
*/
HiddenFieldFactory.prototype.parentFieldFactory;
/**
* @type {?}
* @private
*/
HiddenFieldFactory.prototype.formBuilder;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* A service for creating and rendering dynamic forms. For usage informations refer to
* https://github.com/tom-schoener/angular-dynamic-forms-lite
*/
class DynamicFormsLiteService {
/**
* @param {?} componentFactoryResolver
* @param {?} injector
* @param {?=} defaultFormComponents
*/
constructor(componentFactoryResolver, injector, defaultFormComponents) {
this.componentFactoryResolver = componentFactoryResolver;
this.injector = injector;
this.defaultFormComponents = defaultFormComponents;
}
/**
* Creates a form context from a seperated model and form settings. This is useful for advanced
* forms, where the model is fetched from a server.
*
* @template M
* @param {?} formModel form model
* @param {?} formFieldSettings settings for the form model
* @param {?=} rootSetting settings for the root of the form
* @return {?}
*/
create(formModel, formFieldSettings, rootSetting = this.createRootSetting()) {
/** @type {?} */
const settings = createFormFieldSettings(rootSetting, formFieldSettings, this.defaultFormComponents);
return (/** @type {?} */ (this.createParentFieldFactory(settings).create({
initialValue: formModel,
setting: settings.get(ROOT_ID),
settings
})));
}
/**
* Creates a dynamic form context which can be used to render a form. This is useful for simple forms, where
* the model is basically empty. For an advanced usecase with a seperate model and form settings see 'create'.
*
* @param {?} inlineForm form, where the model and settings are combined
* @param {?=} rootSetting settings for the root of the form
* @return {?}
*/
createInline(inlineForm, rootSetting = this.createRootSetting()) {
/** @type {?} */
const inlineFormFactory = new InlineFormFactory(this.defaultFormComponents);
/** @type {?} */
const settings = inlineFormFactory.resolveSettings(inlineForm);
/** @type {?} */
const formModel = inlineFormFactory.resolveModel(inlineForm);
return this.create(formModel, settings, rootSetting);
}
/**
* Renders the form at the specified form root recursively.
*
* @param {?} formRoot root element (directive) to insert the form into
* @param {?} formContext form context
* @return {?}
*/
render(formRoot, formContext) {
this.createParentFieldFactory(formContext.settings).render(formRoot, formContext);
}
/**
* @private
* @return {?}
*/
createRootSetting() {
return {
component: (/** @type {?} */ (ensureDefaultFormComponents(this.defaultFormComponents, "root", DynamicFormType.GROUP))),
metadata: null
};
}
/**
* @private
* @param {?} settings
* @return {?}
*/
createParentFieldFactory(settings) {
return new ParentFieldFactory({
[DynamicFormType.GROUP]: GroupFieldFactory,
[DynamicFormType.ARRAY]: ArrayFieldFactory,
[DynamicFormType.SINGLE]: SingleFieldFactory,
[DynamicFormType.HIDDEN]: HiddenFieldFactory
}, this.componentFactoryResolver, this.injector, new FormBuilder(), settings);
}
}
DynamicFormsLiteService.decorators = [
{ type: Injectable, args: [{