ngx-schema-forms
Version:
New features: - Ajv schema validator. - Angular forms compatible: Property tree is created using FormGroup, FormArray and FormControl classes. - Array now properly loads initial data from model. - WidgetTyep: WidgetRegistry now supports WidgetType, now wo
1,677 lines (1,657 loc) • 320 kB
JavaScript
import { ComponentFactoryResolver, Injectable, EventEmitter, Component, Input, forwardRef, ChangeDetectorRef, ViewEncapsulation, TemplateRef, Directive, ViewContainerRef, Injector, NgModule, Output, ElementRef, ContentChildren, SimpleChange } from '@angular/core';
import { __extends, __spread, __decorate, __metadata, __values } from 'tslib';
import { BehaviorSubject, combineLatest, merge } from 'rxjs';
import { map, startWith, filter, distinctUntilChanged } from 'rxjs/operators';
import { FormControl, FormArray, FormGroup, NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms';
import * as ZSchema from 'z-schema';
import * as Ajv from 'ajv';
import { CommonModule } from '@angular/common';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var ActionRegistry = /** @class */ (function () {
function ActionRegistry() {
this.actions = {};
}
/**
* @return {?}
*/
ActionRegistry.prototype.clear = /**
* @return {?}
*/
function () {
this.actions = {};
};
/**
* @param {?} actionId
* @param {?} action
* @return {?}
*/
ActionRegistry.prototype.register = /**
* @param {?} actionId
* @param {?} action
* @return {?}
*/
function (actionId, action) {
this.actions[actionId] = action;
};
/**
* @param {?} actionId
* @return {?}
*/
ActionRegistry.prototype.get = /**
* @param {?} actionId
* @return {?}
*/
function (actionId) {
return this.actions[actionId];
};
return ActionRegistry;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var ValidatorRegistry = /** @class */ (function () {
function ValidatorRegistry() {
this.validators = {};
}
/**
* @param {?} path
* @param {?} validator
* @return {?}
*/
ValidatorRegistry.prototype.register = /**
* @param {?} path
* @param {?} validator
* @return {?}
*/
function (path, validator) {
this.validators[path] = validator;
};
/**
* @param {?} path
* @return {?}
*/
ValidatorRegistry.prototype.get = /**
* @param {?} path
* @return {?}
*/
function (path) {
return this.validators[path];
};
/**
* @return {?}
*/
ValidatorRegistry.prototype.clear = /**
* @return {?}
*/
function () {
this.validators = {};
};
return ValidatorRegistry;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/** @enum {string} */
var SchemaPropertyType = {
String: 'string',
Object: 'object',
Array: 'array',
Boolean: 'boolean',
Integer: 'integer',
Number: 'number',
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @abstract
*/
var /**
* @abstract
*/
SchemaValidatorFactory = /** @class */ (function () {
function SchemaValidatorFactory() {
}
return SchemaValidatorFactory;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/** @enum {string} */
var WidgetType = {
Field: 'field',
Fieldset: 'fieldset',
Button: 'button',
};
var WidgetRegistry = /** @class */ (function () {
function WidgetRegistry() {
this.widgets = {};
this.defaultWidget = {};
}
/**
* @param {?} widget
* @param {?=} type
* @return {?}
*/
WidgetRegistry.prototype.setDefaultWidget = /**
* @param {?} widget
* @param {?=} type
* @return {?}
*/
function (widget, type) {
if (type === void 0) { type = WidgetType.Field; }
this.defaultWidget[type] = widget;
};
/**
* @param {?=} type
* @return {?}
*/
WidgetRegistry.prototype.getDefaultWidget = /**
* @param {?=} type
* @return {?}
*/
function (type) {
if (type === void 0) { type = WidgetType.Field; }
return this.defaultWidget[type];
};
/**
* @param {?} id
* @param {?=} type
* @return {?}
*/
WidgetRegistry.prototype.hasWidget = /**
* @param {?} id
* @param {?=} type
* @return {?}
*/
function (id, type) {
if (type === void 0) { type = WidgetType.Field; }
if (!this.widgets.hasOwnProperty(type)) {
return false;
}
return this.widgets[type].hasOwnProperty(id);
};
/**
* @param {?} id
* @param {?} widget
* @param {?=} type
* @return {?}
*/
WidgetRegistry.prototype.register = /**
* @param {?} id
* @param {?} widget
* @param {?=} type
* @return {?}
*/
function (id, widget, type) {
if (type === void 0) { type = WidgetType.Field; }
if (!this.widgets.hasOwnProperty(type)) {
this.widgets[type] = {};
}
this.widgets[type][id] = widget;
};
/**
* @template T
* @param {?} id
* @param {?=} type
* @return {?}
*/
WidgetRegistry.prototype.getWidgetType = /**
* @template T
* @param {?} id
* @param {?=} type
* @return {?}
*/
function (id, type) {
if (type === void 0) { type = WidgetType.Field; }
if (this.hasWidget(id, type)) {
return this.widgets[type][id];
}
return this.getDefaultWidget(type);
};
return WidgetRegistry;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var WidgetFactory = /** @class */ (function () {
function WidgetFactory(widgetRegistry, factoryResolver) {
this.widgetRegistry = widgetRegistry;
this.factoryResolver = factoryResolver;
}
/**
* @template T
* @param {?} container
* @param {?} id
* @param {?=} opts
* @return {?}
*/
WidgetFactory.prototype.createWidget = /**
* @template T
* @param {?} container
* @param {?} id
* @param {?=} opts
* @return {?}
*/
function (container, id, opts) {
if (opts === void 0) { opts = {
type: WidgetType.Field
}; }
/** @type {?} */
var componentClass = this.widgetRegistry.getWidgetType(id, opts.type);
/** @type {?} */
var componentFactory = this.factoryResolver
.resolveComponentFactory(componentClass);
return container.createComponent(componentFactory, undefined, // index
// index
opts.injector);
};
WidgetFactory.decorators = [
{ type: Injectable }
];
/** @nocollapse */
WidgetFactory.ctorParameters = function () { return [
{ type: WidgetRegistry },
{ type: ComponentFactoryResolver }
]; };
return WidgetFactory;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var FormPropertyErrors = /** @class */ (function () {
function FormPropertyErrors(errors) {
this.errors = errors;
}
/**
* @return {?}
*/
FormPropertyErrors.prototype.getMessages = /**
* @return {?}
*/
function () {
var _this = this;
/** @type {?} */
var errorsPaths = Object.keys(this.errors);
if (!errorsPaths.length) {
return [];
}
return errorsPaths
.reduce(function (messages, path) {
/** @type {?} */
var message = _this.errors[path]["message"];
if (!message) {
messages.push('Missing validation error "message" for property ' + path);
return messages;
}
messages.push(message);
return messages;
}, []);
};
return FormPropertyErrors;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @template T
* @param {?} Base
* @return {?}
*/
function ControlProperty(Base) {
/**
* @abstract
*/
var /**
* @abstract
*/
Property = /** @class */ (function (_super) {
__extends(Property, _super);
function Property() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var _this = _super.apply(this, __spread(args)) || this;
_this.nonEmptyValueChanges = new EventEmitter();
_this.visibilityChanges = new BehaviorSubject(true);
_this._visible = true;
return _this;
}
Object.defineProperty(Property.prototype, "id", {
get: /**
* @return {?}
*/
function () {
return this.path.toLowerCase().slice(1).replace(/\//g, '-');
},
enumerable: true,
configurable: true
});
Object.defineProperty(Property.prototype, "isRoot", {
get: /**
* @return {?}
*/
function () {
return this === this.root;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Property.prototype, "name", {
get: /**
* @return {?}
*/
function () {
return this.path.split('/').pop();
},
enumerable: true,
configurable: true
});
Object.defineProperty(Property.prototype, "visible", {
get: /**
* @return {?}
*/
function () {
return this._visible;
},
enumerable: true,
configurable: true
});
/**
* @return {?}
*/
Property.prototype.getErrors = /**
* @return {?}
*/
function () {
/** @type {?} */
var errors = this.errors;
if (!errors) {
return null;
}
return new FormPropertyErrors((_a = {}, _a[this.path] = errors, _a));
var _a;
};
/**
* @param {?} visible
* @param {?=} opts
* @return {?}
*/
Property.prototype.setVisible = /**
* @param {?} visible
* @param {?=} opts
* @return {?}
*/
function (visible, opts) {
if (opts === void 0) { opts = { disable: false }; }
this._visible = visible;
if (opts.disable) {
if (this.visible) {
this.enable();
}
else {
this.disable();
}
}
this.visibilityChanges.next(this.visible);
};
// visible if AT LEAST ONE of the properties it depends on is visible
// AND has a value in the list
/**
* @return {?}
*/
Property.prototype.bindVisibility = /**
* @return {?}
*/
function () {
var _this = this;
/** @type {?} */
var visibleIf = this.schema["visibleIf"];
if (visibleIf === undefined) {
return;
}
/** @type {?} */
var paths = Object.keys(visibleIf);
if (typeof visibleIf === 'object' && paths.length === 0) {
this.setVisible(false);
return;
}
/** @type {?} */
var observables = [];
var _loop_1 = function (path) {
if (!visibleIf.hasOwnProperty(path)) {
return "continue";
}
/** @type {?} */
var property = this_1.root.get(path);
if (!property) {
console.warn("Couldn't find property " + path + " for visibility check of " + this_1.path);
return "continue";
}
/** @type {?} */
var values = visibleIf[path];
/** @type {?} */
var observable = property.valueChanges.pipe(startWith(values.includes(property.value)), map(function (value) {
return values.includes('$ANY$') || values.includes(value);
}));
observables.push(observable);
};
var this_1 = this;
try {
for (var paths_1 = __values(paths), paths_1_1 = paths_1.next(); !paths_1_1.done; paths_1_1 = paths_1.next()) {
var path = paths_1_1.value;
_loop_1(path);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (paths_1_1 && !paths_1_1.done && (_a = paths_1.return)) _a.call(paths_1);
}
finally { if (e_1) throw e_1.error; }
}
// TODO unsubscribe
combineLatest(observables)
.subscribe(function (values) {
_this.setVisible(values.includes(true));
});
var e_1, _a;
};
/**
* @param {?} path
* @return {?}
*/
Property.prototype.get = /**
* @param {?} path
* @return {?}
*/
function (path) {
if (typeof path === 'string' && path.includes('/')) {
path = this.normalizePath(path);
}
return _super.prototype.get.call(this, path);
};
/**
* @param {?} path
* @return {?}
*/
Property.prototype.normalizePath = /**
* @param {?} path
* @return {?}
*/
function (path) {
if (path[0] === '/') {
path = path.slice(1);
}
return path.split('/');
};
return Property;
}(Base));
return Property;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var GenericProperty = /** @class */ (function (_super) {
__extends(GenericProperty, _super);
function GenericProperty(path, schema) {
var _this = _super.call(this, schema["default"]) || this;
_this.path = path;
_this.schema = schema;
return _this;
}
/**
* @return {?}
*/
GenericProperty.prototype._updateValue = /**
* @return {?}
*/
function () {
if (this.value === null || this.value === '') {
this.nonEmptyValue = undefined;
return;
}
this.nonEmptyValue = this.value;
};
return GenericProperty;
}(ControlProperty(FormControl)));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var NumberProperty = /** @class */ (function (_super) {
__extends(NumberProperty, _super);
function NumberProperty() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* @param {?} value
* @param {?=} options
* @return {?}
*/
NumberProperty.prototype.setValue = /**
* @param {?} value
* @param {?=} options
* @return {?}
*/
function (value, options) {
if (options === void 0) { options = {}; }
_super.prototype.setValue.call(this, +value, options);
};
return NumberProperty;
}(GenericProperty));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var BooleanProperty = /** @class */ (function (_super) {
__extends(BooleanProperty, _super);
function BooleanProperty() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* @param {?} value
* @param {?=} options
* @return {?}
*/
BooleanProperty.prototype.setValue = /**
* @param {?} value
* @param {?=} options
* @return {?}
*/
function (value, options) {
if (options === void 0) { options = {}; }
if (typeof value !== 'boolean') {
value = Boolean(value);
}
_super.prototype.setValue.call(this, value, options);
};
return BooleanProperty;
}(GenericProperty));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var StringProperty = /** @class */ (function (_super) {
__extends(StringProperty, _super);
function StringProperty() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* @param {?} value
* @param {?=} options
* @return {?}
*/
StringProperty.prototype.setValue = /**
* @param {?} value
* @param {?=} options
* @return {?}
*/
function (value, options) {
if (options === void 0) { options = {}; }
if (typeof value !== 'string') {
value = "" + value;
}
_super.prototype.setValue.call(this, value, options);
};
return StringProperty;
}(GenericProperty));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var ArrayProperty = /** @class */ (function (_super) {
__extends(ArrayProperty, _super);
function ArrayProperty(formPropertyFactory, path, schema) {
var _this = _super.call(this, []) || this;
_this.formPropertyFactory = formPropertyFactory;
_this.path = path;
_this.schema = schema;
return _this;
}
/**
* @return {?}
*/
ArrayProperty.prototype._updateValue = /**
* @return {?}
*/
function () {
var _this = this;
// to avoid ts complaints
_super.prototype['_updateValue'].call(this);
this.nonEmptyValue = this.controls
.filter(function (control) {
/** @type {?} */
var enabled = control.enabled || _this.disabled;
return control.nonEmptyValue !== undefined && enabled;
})
.map(function (control) { return control.value; });
};
/**
* @return {?}
*/
ArrayProperty.prototype.getErrors = /**
* @return {?}
*/
function () {
/** @type {?} */
var aggregatedErrors = this.controls
.reduce(function (errors, property) {
/** @type {?} */
var propertyErrors = property.getErrors();
if (!propertyErrors) {
return errors;
}
return Object.assign(errors, propertyErrors.errors);
}, {});
if (this.errors) {
aggregatedErrors[this.path] = this.errors;
}
if (!Object.keys(aggregatedErrors).length) {
return null;
}
return new FormPropertyErrors(aggregatedErrors);
};
/**
* @param {?} value
* @param {?=} options
* @return {?}
*/
ArrayProperty.prototype.patchValue = /**
* @param {?} value
* @param {?=} options
* @return {?}
*/
function (value, options) {
var _this = this;
if (options === void 0) { options = {}; }
value.forEach(function (newValue, index) {
_this.addPropertyAt(index);
if (_this.at(index)) {
_this.at(index).patchValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
}
});
this.updateValueAndValidity(options);
};
/**
* @return {?}
*/
ArrayProperty.prototype.addProperty = /**
* @return {?}
*/
function () {
/** @type {?} */
var property = this.getPropertyFromSchemaItems();
_super.prototype.push.call(this, property);
property.bindVisibility();
};
/**
* @param {?} index
* @return {?}
*/
ArrayProperty.prototype.addPropertyAt = /**
* @param {?} index
* @return {?}
*/
function (index) {
/** @type {?} */
var property = this.getPropertyFromSchemaItems();
this.insert(index, property);
property.bindVisibility();
};
/**
* @return {?}
*/
ArrayProperty.prototype.bindVisibility = /**
* @return {?}
*/
function () {
_super.prototype.bindVisibility.call(this);
this.controls.forEach(function (control) {
control.bindVisibility();
});
};
/**
* @param {?} fn
* @param {?=} opts
* @return {?}
*/
ArrayProperty.prototype.forEach = /**
* @param {?} fn
* @param {?=} opts
* @return {?}
*/
function (fn, opts) {
if (opts === void 0) { opts = { includeSelf: true }; }
if (opts.includeSelf) {
fn(this);
}
try {
for (var _a = __values(this.controls), _b = _a.next(); !_b.done; _b = _a.next()) {
var control = _b.value;
/** @type {?} */
var property = /** @type {?} */ (control);
if (property.forEach instanceof Function) {
property.forEach(fn, { includeSelf: true });
continue;
}
fn(property);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
}
finally { if (e_1) throw e_1.error; }
}
var e_1, _c;
};
/**
* @return {?}
*/
ArrayProperty.prototype.getPropertyFromSchemaItems = /**
* @return {?}
*/
function () {
return this.formPropertyFactory.createProperty(this.schema["items"], this);
};
return ArrayProperty;
}(ControlProperty(FormArray)));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var ObjectProperty = /** @class */ (function (_super) {
__extends(ObjectProperty, _super);
function ObjectProperty(path, schema) {
var _this = _super.call(this, {}) || this;
_this.path = path;
_this.schema = schema;
return _this;
}
/**
* @return {?}
*/
ObjectProperty.prototype._updateValue = /**
* @return {?}
*/
function () {
var _this = this;
// to avoid ts complaints
_super.prototype['_updateValue'].call(this);
this.nonEmptyValue = this['_reduceChildren']({}, function (result, control, name) {
if (control.nonEmptyValue === undefined) {
return result;
}
if (control.enabled || _this.disabled) {
result[name] = control.nonEmptyValue;
}
return result;
});
};
/**
* @return {?}
*/
ObjectProperty.prototype.getErrors = /**
* @return {?}
*/
function () {
var _this = this;
/** @type {?} */
var aggregatedErrors = Object.keys(this.controls)
.reduce(function (errors, key) {
/** @type {?} */
var property = /** @type {?} */ (_this.controls[key]);
/** @type {?} */
var propertyErrors = property.getErrors();
if (!propertyErrors) {
return errors;
}
return Object.assign(errors, propertyErrors.errors);
}, {});
if (this.errors) {
aggregatedErrors[this.path] = this.errors;
}
if (!Object.keys(aggregatedErrors).length) {
return null;
}
return new FormPropertyErrors(aggregatedErrors);
};
/**
* @return {?}
*/
ObjectProperty.prototype.bindVisibility = /**
* @return {?}
*/
function () {
_super.prototype.bindVisibility.call(this);
for (var key in this.controls) {
if (this.controls.hasOwnProperty(key)) {
(/** @type {?} */ (this.controls[key])).bindVisibility();
}
}
};
/**
* @param {?} fn
* @param {?=} opts
* @return {?}
*/
ObjectProperty.prototype.forEach = /**
* @param {?} fn
* @param {?=} opts
* @return {?}
*/
function (fn, opts) {
if (opts === void 0) { opts = { includeSelf: true }; }
if (opts.includeSelf) {
fn(this);
}
for (var key in this.controls) {
if (this.controls.hasOwnProperty(key)) {
/** @type {?} */
var property = (/** @type {?} */ (this.controls[key]));
if (property.forEach instanceof Function) {
property.forEach(fn, { includeSelf: true });
continue;
}
fn(property);
}
}
};
return ObjectProperty;
}(ControlProperty(FormGroup)));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @param {?} o
* @return {?}
*/
function isBlank(o) {
return o === null || o === undefined;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @param {?} message
* @param {?} path
* @return {?}
*/
function formatMessage(message, path) {
return "Parsing error on " + path + ": " + message;
}
/**
* @param {?} message
* @param {?} path
* @return {?}
*/
function schemaError(message, path) {
/** @type {?} */
var mesg = formatMessage(message, path);
throw new Error(mesg);
}
/**
* @param {?} message
* @param {?} path
* @return {?}
*/
function schemaWarning(message, path) {
/** @type {?} */
var mesg = formatMessage(message, path);
throw new Error(mesg);
}
var SchemaPreprocessor = /** @class */ (function () {
function SchemaPreprocessor() {
}
/**
* @param {?} jsonSchema
* @param {?=} path
* @return {?}
*/
SchemaPreprocessor.preprocess = /**
* @param {?} jsonSchema
* @param {?=} path
* @return {?}
*/
function (jsonSchema, path) {
if (path === void 0) { path = '/'; }
jsonSchema = jsonSchema || {};
if (jsonSchema.type === 'object') {
SchemaPreprocessor.checkProperties(jsonSchema, path);
SchemaPreprocessor.checkAndCreateFieldsets(jsonSchema, path);
}
else if (jsonSchema.type === 'array') {
SchemaPreprocessor.checkItems(jsonSchema, path);
}
SchemaPreprocessor.normalizeWidget(jsonSchema);
SchemaPreprocessor.recursiveCheck(jsonSchema, path);
};
/**
* @param {?} jsonSchema
* @param {?} path
* @return {?}
*/
SchemaPreprocessor.checkProperties = /**
* @param {?} jsonSchema
* @param {?} path
* @return {?}
*/
function (jsonSchema, path) {
if (isBlank(jsonSchema.properties)) {
jsonSchema.properties = {};
schemaWarning('Provided json schema does not contain a \'properties\' entry. Output schema will be empty', path);
}
};
/**
* @param {?} jsonSchema
* @param {?} path
* @return {?}
*/
SchemaPreprocessor.checkAndCreateFieldsets = /**
* @param {?} jsonSchema
* @param {?} path
* @return {?}
*/
function (jsonSchema, path) {
if (jsonSchema.fieldsets === undefined) {
if (jsonSchema.order !== undefined) {
SchemaPreprocessor.replaceOrderByFieldsets(jsonSchema);
}
else {
SchemaPreprocessor.createFieldsets(jsonSchema);
}
}
SchemaPreprocessor.checkFieldsUsage(jsonSchema, path);
};
/**
* @param {?} jsonSchema
* @param {?} path
* @return {?}
*/
SchemaPreprocessor.checkFieldsUsage = /**
* @param {?} jsonSchema
* @param {?} path
* @return {?}
*/
function (jsonSchema, path) {
/** @type {?} */
var fieldsId = Object.keys(jsonSchema.properties);
/** @type {?} */
var usedFields = {};
try {
for (var _a = __values(jsonSchema.fieldsets), _b = _a.next(); !_b.done; _b = _a.next()) {
var fieldset = _b.value;
try {
for (var _c = __values(fieldset.fields), _d = _c.next(); !_d.done; _d = _c.next()) {
var fieldId = _d.value;
if (usedFields[fieldId] === undefined) {
usedFields[fieldId] = [];
}
usedFields[fieldId].push(fieldset.id);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_d && !_d.done && (_e = _c.return)) _e.call(_c);
}
finally { if (e_1) throw e_1.error; }
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_b && !_b.done && (_f = _a.return)) _f.call(_a);
}
finally { if (e_2) throw e_2.error; }
}
try {
for (var fieldsId_1 = __values(fieldsId), fieldsId_1_1 = fieldsId_1.next(); !fieldsId_1_1.done; fieldsId_1_1 = fieldsId_1.next()) {
var fieldId = fieldsId_1_1.value;
if (usedFields.hasOwnProperty(fieldId)) {
if (usedFields[fieldId].length > 1) {
schemaError(fieldId + " is referenced by more than one fieldset: " + usedFields[fieldId], path);
}
delete usedFields[fieldId];
}
else if (jsonSchema.required.indexOf(fieldId) > -1) {
schemaError(fieldId + " is a required field but it is not referenced as part of a 'order' or a 'fieldset' property", path);
}
else {
delete jsonSchema[fieldId];
schemaWarning("Removing unreferenced field " + fieldId, path);
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (fieldsId_1_1 && !fieldsId_1_1.done && (_g = fieldsId_1.return)) _g.call(fieldsId_1);
}
finally { if (e_3) throw e_3.error; }
}
for (var remainingfieldsId in usedFields) {
if (usedFields.hasOwnProperty(remainingfieldsId)) {
schemaWarning("Referencing non-existent field " + remainingfieldsId + " in one or more fieldsets", path);
}
}
var e_2, _f, e_1, _e, e_3, _g;
};
/**
* @param {?} jsonSchema
* @return {?}
*/
SchemaPreprocessor.createFieldsets = /**
* @param {?} jsonSchema
* @return {?}
*/
function (jsonSchema) {
jsonSchema.order = Object.keys(jsonSchema.properties);
SchemaPreprocessor.replaceOrderByFieldsets(jsonSchema);
};
/**
* @param {?} jsonSchema
* @return {?}
*/
SchemaPreprocessor.replaceOrderByFieldsets = /**
* @param {?} jsonSchema
* @return {?}
*/
function (jsonSchema) {
jsonSchema.fieldsets = [{
id: 'fieldset-default',
title: jsonSchema.title || '',
description: jsonSchema.description || '',
name: jsonSchema.name || '',
fields: jsonSchema.order
}];
delete jsonSchema.order;
};
/**
* @param {?} fieldSchema
* @return {?}
*/
SchemaPreprocessor.normalizeWidget = /**
* @param {?} fieldSchema
* @return {?}
*/
function (fieldSchema) {
/** @type {?} */
var widget = fieldSchema.widget;
if (widget === undefined) {
widget = { 'id': fieldSchema.type };
}
else if (typeof widget === 'string') {
widget = { 'id': widget };
}
fieldSchema.widget = widget;
};
/**
* @param {?} jsonSchema
* @param {?} path
* @return {?}
*/
SchemaPreprocessor.checkItems = /**
* @param {?} jsonSchema
* @param {?} path
* @return {?}
*/
function (jsonSchema, path) {
if (jsonSchema.items === undefined) {
schemaError('No \'items\' property in array', path);
}
};
/**
* @param {?} jsonSchema
* @param {?} path
* @return {?}
*/
SchemaPreprocessor.recursiveCheck = /**
* @param {?} jsonSchema
* @param {?} path
* @return {?}
*/
function (jsonSchema, path) {
if (jsonSchema.type === 'object') {
/*
for (const fieldId in jsonSchema.properties) {
if (jsonSchema.properties.hasOwnProperty(fieldId)) {
const fieldSchema = jsonSchema.properties[fieldId];
SchemaPreprocessor.preprocess(fieldSchema, path + fieldId + '/');
}
}
*/
if (jsonSchema.hasOwnProperty('definitions')) {
for (var fieldId in jsonSchema.definitions) {
if (jsonSchema.definitions.hasOwnProperty(fieldId)) {
/** @type {?} */
var fieldSchema = jsonSchema.definitions[fieldId];
SchemaPreprocessor.removeRecursiveRefProperties(fieldSchema, "#/definitions/" + fieldId);
// formPropertyFactory recursive is used instead
// SchemaPreprocessor.preprocess(fieldSchema, path + fieldId + '/');
}
}
}
} // else if (jsonSchema.type === 'array') {
// formPropertyFactory recursive is used instead
// SchemaPreprocessor.preprocess(jsonSchema.items, path + '*/');
// }
};
/**
* @param {?} jsonSchema
* @param {?} definitionPath
* @return {?}
*/
SchemaPreprocessor.removeRecursiveRefProperties = /**
* @param {?} jsonSchema
* @param {?} definitionPath
* @return {?}
*/
function (jsonSchema, definitionPath) {
// to avoid infinite loop
if (jsonSchema.type === 'object') {
for (var fieldId in jsonSchema.properties) {
if (jsonSchema.properties.hasOwnProperty(fieldId)) {
if (jsonSchema.properties[fieldId].$ref
&& jsonSchema.properties[fieldId].$ref === definitionPath) {
delete jsonSchema.properties[fieldId];
}
else if (jsonSchema.properties[fieldId].type === 'object') {
SchemaPreprocessor.removeRecursiveRefProperties(jsonSchema.properties[fieldId], definitionPath);
}
}
}
}
};
return SchemaPreprocessor;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var FormPropertyFactory = /** @class */ (function () {
function FormPropertyFactory(schemaValidatorFactory, validatorRegistry) {
this.schemaValidatorFactory = schemaValidatorFactory;
this.validatorRegistry = validatorRegistry;
}
/**
* @param {?} schema
* @param {?=} propertyParent
* @param {?=} propertyKey
* @return {?}
*/
FormPropertyFactory.prototype.createProperty = /**
* @param {?} schema
* @param {?=} propertyParent
* @param {?=} propertyKey
* @return {?}
*/
function (schema, propertyParent, propertyKey) {
/** @type {?} */
var property;
/** @type {?} */
var path = this.generatePath(propertyParent, propertyKey);
SchemaPreprocessor.preprocess(schema, path);
// TODO test for parsing for reference schema
if (schema["$ref"]) {
/** @type {?} */
var refSchema = this.schemaValidatorFactory.getSchema((/** @type {?} */ (propertyParent.root)).schema, schema["$ref"]);
property = this.createProperty(refSchema, propertyParent, propertyKey || path);
}
else {
switch (schema["type"]) {
case SchemaPropertyType.Integer:
case SchemaPropertyType.Number:
property = new NumberProperty(path, schema);
break;
case SchemaPropertyType.String:
property = new StringProperty(path, schema);
break;
case SchemaPropertyType.Boolean:
property = new BooleanProperty(path, schema);
break;
case SchemaPropertyType.Object:
property = new ObjectProperty(path, schema);
break;
case SchemaPropertyType.Array:
if (schema["widget"].id === 'array') {
property = new ArrayProperty(this, path, schema);
}
else {
schema["default"] = [];
property = new GenericProperty(path, schema);
}
break;
default:
throw new TypeError("Undefined type " + schema["type"]);
}
}
this.initializeFormProperty(property, propertyParent);
return property;
};
/**
* @param {?} property
* @param {?=} propertyParent
* @return {?}
*/
FormPropertyFactory.prototype.initializeFormProperty = /**
* @param {?} property
* @param {?=} propertyParent
* @return {?}
*/
function (property, propertyParent) {
if (propertyParent) {
property.setParent(propertyParent);
}
this.bindCustomValidator(property);
if (property instanceof ObjectProperty) {
for (var key in property.schema["properties"]) {
if (property.schema["properties"].hasOwnProperty(key)) {
/** @type {?} */
var _schema = property.schema["properties"][key];
/** @type {?} */
var _property = this.createProperty(_schema, property, key);
property.addControl(key, _property);
}
}
}
if (property.isRoot) {
this.bindSchemaValidator(property);
// needs to run after entire property tree is built
property.bindVisibility();
}
};
/**
* @param {?} property
* @return {?}
*/
FormPropertyFactory.prototype.bindSchemaValidator = /**
* @param {?} property
* @return {?}
*/
function (property) {
/** @type {?} */
var validate = this.schemaValidatorFactory.createValidatorFn(property.schema);
// TODO use pipe startWith to do initial run
property.valueChanges
.pipe(startWith(null))
.subscribe(function () {
/** @type {?} */
var value = property.nonEmptyValue;
property.nonEmptyValueChanges.emit(value);
/** @type {?} */
var errors = validate(value);
if (!errors) {
return;
}
Object.keys(errors).forEach(function (path) {
/** @type {?} */
var control = property.get(path);
if (control) {
// set error to specific control
control.setErrors(errors[path], { emitEvent: true });
}
});
});
};
/**
* @param {?} property
* @return {?}
*/
FormPropertyFactory.prototype.bindCustomValidator = /**
* @param {?} property
* @return {?}
*/
function (property) {
/** @type {?} */
var validators = this.validatorRegistry.get(property.path);
if (validators) {
property.setValidators(validators);
}
};
/**
* @param {?=} propertyParent
* @param {?=} propertyKey
* @return {?}
*/
FormPropertyFactory.prototype.generatePath = /**
* @param {?=} propertyParent
* @param {?=} propertyKey
* @return {?}
*/
function (propertyParent, propertyKey) {
if (!propertyParent) {
return '/';
}
/** @type {?} */
var path = '';
path += propertyParent.path;
if (propertyParent.parent !== undefined) {
path += '/';
}
switch (propertyParent.schema["type"]) {
case SchemaPropertyType.Object:
path += propertyKey;
break;
case SchemaPropertyType.Array:
path += (/** @type {?} */ (propertyParent)).controls.length;
break;
default:
// TODO move to class
throw new Error('Instantiation of a FormProperty with an unknown parent type: ' + propertyParent.schema["type"]);
}
return path;
};
return FormPropertyFactory;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/** @enum {string} */
var TemplateElementType = {
Field: 'field',
Button: 'button',
};
var TemplateSchemaElementRegistry = /** @class */ (function () {
function TemplateSchemaElementRegistry() {
this.elements = {};
}
/**
* @param {?} id
* @param {?=} type
* @return {?}
*/
TemplateSchemaElementRegistry.prototype.hasElement = /**
* @param {?} id
* @param {?=} type
* @return {?}
*/
function (id, type) {
if (type === void 0) { type = TemplateElementType.Field; }
if (!this.elements.hasOwnProperty(type)) {
return false;
}
return this.elements[type].hasOwnProperty(id);
};
/**
* @param {?} id
* @param {?} element
* @param {?=} type
* @return {?}
*/
TemplateSchemaElementRegistry.prototype.register = /**
* @param {?} id
* @param {?} element
* @param {?=} type
* @return {?}
*/
function (id, element, type) {
if (type === void 0) { type = TemplateElementType.Field; }
if (!this.elements.hasOwnProperty(type)) {
this.elements[type] = {};
}
this.elements[type][id] = element;
};
/**
* @template T
* @param {?} id
* @param {?=} type
* @return {?}
*/
TemplateSchemaElementRegistry.prototype.getElement = /**
* @template T
* @param {?} id
* @param {?=} type
* @return {?}
*/
function (id, type) {
if (type === void 0) { type = TemplateElementType.Field; }
if (this.hasElement(id, type)) {
return this.elements[type][id];
}
};
/**
* @return {?}
*/
TemplateSchemaElementRegistry.prototype.clear = /**
* @return {?}
*/
function () {
this.elements = {};
};
return TemplateSchemaElementRegistry;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @param {?} schemaValidatorFactory
* @param {?} validatorRegistry
* @return {?}
*/
function useFactory(schemaValidatorFactory, validatorRegistry) {
return new FormPropertyFactory(schemaValidatorFactory, validatorRegistry);
}
var FormComponent = /** @class */ (function () {
function FormComponent(changeDetectorRef, formPropertyFactory, actionRegistry, validatorRegistry) {
this.changeDetectorRef = changeDetectorRef;
this.formPropertyFactory = formPropertyFactory;
this.actionRegistry = actionRegistry;
this.validatorRegistry = validatorRegistry;
this.schema = null;
this.actions = {};
this.validators = {};
this.rootFormProperty = null;
}
/**
* @param {?} value
* @return {?}
*/
FormComponent.prototype.writeValue = /**
* @param {?} value
* @return {?}
*/
function (value) {
// value should be object
if (this.rootFormProperty && value) {
this.rootFormProperty.patchValue(value);
}
};
/**
* @param {?} fn
* @return {?}
*/
FormComponent.prototype.registerOnChange = /**
* @param {?} fn
* @return {?}
*/
function (fn) {
this.onChangeCallback = fn;
if (this.rootFormProperty) {
this.rootFormProperty.nonEmptyValueChanges.subscribe(fn);
}
};
// TODO implement
/**
* @param {?} fn
* @return {?}
*/
FormComponent.prototype.registerOnTouched = /**
* @param {?} fn
* @return {?}
*/
function (fn) { };
/**
* @param {?} isDisabled
* @return {?}
*/
FormComponent.prototype.setDisabledState = /**
* @param {?} isDisabled
* @return {?}
*/
function (isDisabled) {
if (!this.rootFormProperty) {
return;
}
if (isDisabled) {
this.rootFormProperty.disable();
}
else {
this.rootFormProperty.enable();
}
};
/**
* @param {?} changes
* @return {?}
*/
FormComponent.prototype.ngOnChanges = /**
* @param {?} changes
* @return {?}
*/
function (changes) {
if (changes["validators"]) {
this.registerValidators();
}
if (changes["actions"]) {
this.registerActions();
}
if (this.schema && !this.schema.type) {
this.schema.type = SchemaPropertyType.Object;
}
if (this.schema && changes["schema"]) {
/** @type {?} */
var value = void 0;
if (this.rootFormProperty) {
// TODO validate model against schema
value = this.rootFormProperty.nonEmptyValue;
}
// force component destruction
this.rootFormProperty = null;
this.changeDetectorRef.detectChanges();
/** @type {?} */
var rootFormProperty = this.formPropertyFactory.createProperty(this.schema);
// registerOnChange for changes after init
if (this.onChangeCallback) {
rootFormProperty.nonEmptyValueChanges.subscribe(this.onChangeCallback);
if (value) {
rootFormProperty.patchValue(value);
}
}
this.rootFormProperty = rootFormProperty;
}
};
/**
* @return {?}
*/
FormComponent.prototype.ngOnInit = /**
* @return {?}
*/
function () {
};
/**
* @return {?}
*/
FormComponent.prototype.registerValidators = /**
* @return {?}
*/
function () {
this.validatorRegistry.clear();
if (!this.validators) {
return;
}
for (var propertyPath in this.validators) {
if (this.validators.hasOwnProperty(propertyPath)) {
this.validatorRegistry.register(propertyPath, this.validators[propertyPath]);
}
}
};
/**
* @return {?}
*/
FormComponent.prototype.registerActions = /**
* @return {?}
*/
function () {
this.actionRegistry.clear();
if (!this.actions) {
return;
}
for (var actionId in this.actions) {
if (this.actions.hasOwnProperty(actionId)) {
this.actionRegistry.register(actionId, this.actions[actionId]);
}
}
};
FormComponent.decorators = [
{ type: Component, args: [{
selector: 'sf-form',
template: "\n <form #form=\"ngForm\">\n <sf-form-element *ngIf=\"rootFormProperty; else noSchema\" [formProperty]=\"rootFormProperty\">\n </sf-form-element>\n <ng-template #noSchema>\n You need to provide a json or a template schema!\n </ng-template>\n </form>\n ",
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(function () { return FormComponent; }),
multi: true
},
ActionRegistry,
ValidatorRegistry,
WidgetFactory,
{
provide: FormPropertyFactory,
useFactory: useFactory,
deps: [SchemaValidatorFactory, ValidatorRegistry]
},
TemplateSchemaElementRegistry
],
encapsulation: ViewEncapsulation.None
}] }
];
/** @nocollapse */
FormComponent.ctorParameters = function () { return [
{ type: ChangeDetectorRef },
{ type: FormPropertyFactory },
{ type: ActionRegistry },
{ type: ValidatorRegistry }
]; };
FormComponent.propDecorators = {
schema: [{ type: Input }],
actions: [{ type: Input }],
validators: [{ type: Input }]
};
return FormComponent;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @abstract
*/
var /**
* @abstract
*/
FormElementTemplateRef = /** @class */ (function (_super) {
__extends(FormElementTemplateRef, _super);
function FormElementTemplateRef() {
return _super !== null && _super.apply(this, arguments) || this;
}
return FormElementTemplateRef;
}(TemplateRef));