@ng-formworks/core 17.2.7 → 17.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +836 -0
- package/esm2022/lib/framework-library/framework-library.service.mjs +175 -0
- package/esm2022/lib/framework-library/framework.mjs +15 -0
- package/esm2022/lib/framework-library/no-framework.component.mjs +18 -0
- package/esm2022/lib/framework-library/no-framework.module.mjs +27 -0
- package/esm2022/lib/framework-library/no.framework.mjs +19 -0
- package/esm2022/lib/json-schema-form.component.mjs +765 -0
- package/esm2022/lib/json-schema-form.module.mjs +26 -0
- package/esm2022/lib/json-schema-form.service.mjs +679 -0
- package/esm2022/lib/locale/de-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/en-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/es-validation-messages.mjs +57 -0
- package/esm2022/lib/locale/fr-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/index.mjs +8 -0
- package/esm2022/lib/locale/it-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/pt-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/zh-validation-messages.mjs +60 -0
- package/esm2022/lib/shared/convert-schema-to-draft6.function.mjs +300 -0
- package/esm2022/lib/shared/form-group.functions.mjs +442 -0
- package/esm2022/lib/shared/format-regex.constants.mjs +54 -0
- package/esm2022/lib/shared/index.mjs +12 -0
- package/esm2022/lib/shared/json-schema.functions.mjs +784 -0
- package/esm2022/lib/shared/json.validators.mjs +884 -0
- package/esm2022/lib/shared/jsonpointer.functions.mjs +1026 -0
- package/esm2022/lib/shared/layout.functions.mjs +1154 -0
- package/esm2022/lib/shared/merge-schemas.function.mjs +345 -0
- package/esm2022/lib/shared/utility.functions.mjs +380 -0
- package/esm2022/lib/shared/validator.functions.mjs +584 -0
- package/esm2022/lib/widget-library/add-reference.component.mjs +61 -0
- package/esm2022/lib/widget-library/button.component.mjs +72 -0
- package/esm2022/lib/widget-library/checkbox.component.mjs +105 -0
- package/esm2022/lib/widget-library/checkboxes.component.mjs +147 -0
- package/esm2022/lib/widget-library/file.component.mjs +35 -0
- package/esm2022/lib/widget-library/hidden.component.mjs +54 -0
- package/esm2022/lib/widget-library/index.mjs +55 -0
- package/esm2022/lib/widget-library/input.component.mjs +119 -0
- package/esm2022/lib/widget-library/message.component.mjs +38 -0
- package/esm2022/lib/widget-library/none.component.mjs +21 -0
- package/esm2022/lib/widget-library/number.component.mjs +123 -0
- package/esm2022/lib/widget-library/one-of.component.mjs +35 -0
- package/esm2022/lib/widget-library/orderable.directive.mjs +123 -0
- package/esm2022/lib/widget-library/radios.component.mjs +153 -0
- package/esm2022/lib/widget-library/root.component.mjs +79 -0
- package/esm2022/lib/widget-library/section.component.mjs +199 -0
- package/esm2022/lib/widget-library/select-framework.component.mjs +51 -0
- package/esm2022/lib/widget-library/select-widget.component.mjs +46 -0
- package/esm2022/lib/widget-library/select.component.mjs +150 -0
- package/esm2022/lib/widget-library/submit.component.mjs +82 -0
- package/esm2022/lib/widget-library/tab.component.mjs +41 -0
- package/esm2022/lib/widget-library/tabs.component.mjs +108 -0
- package/esm2022/lib/widget-library/template.component.mjs +46 -0
- package/esm2022/lib/widget-library/textarea.component.mjs +104 -0
- package/esm2022/lib/widget-library/widget-library.module.mjs +42 -0
- package/esm2022/lib/widget-library/widget-library.service.mjs +226 -0
- package/esm2022/ng-formworks-core.mjs +5 -0
- package/esm2022/public_api.mjs +13 -0
- package/fesm2022/ng-formworks-core.mjs +10149 -0
- package/fesm2022/ng-formworks-core.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/framework-library/framework-library.service.d.ts +55 -0
- package/lib/framework-library/framework.d.ts +13 -0
- package/lib/framework-library/no-framework.component.d.ts +8 -0
- package/lib/framework-library/no-framework.module.d.ts +9 -0
- package/lib/framework-library/no.framework.d.ts +10 -0
- package/lib/json-schema-form.component.d.ts +218 -0
- package/lib/json-schema-form.module.d.ts +11 -0
- package/lib/json-schema-form.service.d.ts +115 -0
- package/lib/locale/de-validation-messages.d.ts +1 -0
- package/lib/locale/en-validation-messages.d.ts +1 -0
- package/lib/locale/es-validation-messages.d.ts +1 -0
- package/lib/locale/fr-validation-messages.d.ts +1 -0
- package/{src/lib/locale/index.ts → lib/locale/index.d.ts} +7 -7
- package/lib/locale/it-validation-messages.d.ts +1 -0
- package/lib/locale/pt-validation-messages.d.ts +1 -0
- package/lib/locale/zh-validation-messages.d.ts +1 -0
- package/lib/shared/convert-schema-to-draft6.function.d.ts +21 -0
- package/lib/shared/form-group.functions.d.ts +100 -0
- package/lib/shared/format-regex.constants.d.ts +19 -0
- package/lib/shared/index.d.ts +9 -0
- package/lib/shared/json-schema.functions.d.ts +193 -0
- package/lib/shared/json.validators.d.ts +441 -0
- package/lib/shared/jsonpointer.functions.d.ts +416 -0
- package/lib/shared/layout.functions.d.ts +83 -0
- package/lib/shared/merge-schemas.function.d.ts +19 -0
- package/lib/shared/utility.functions.d.ts +165 -0
- package/{src/lib/shared/validator.functions.ts → lib/shared/validator.functions.d.ts} +364 -601
- package/lib/widget-library/add-reference.component.d.ts +20 -0
- package/lib/widget-library/button.component.d.ts +21 -0
- package/lib/widget-library/checkbox.component.d.ts +24 -0
- package/lib/widget-library/checkboxes.component.d.ts +24 -0
- package/lib/widget-library/file.component.d.ts +21 -0
- package/lib/widget-library/hidden.component.d.ts +19 -0
- package/{src/lib/widget-library/index.ts → lib/widget-library/index.d.ts} +47 -56
- package/lib/widget-library/input.component.d.ts +22 -0
- package/lib/widget-library/message.component.d.ts +15 -0
- package/lib/widget-library/none.component.d.ts +8 -0
- package/lib/widget-library/number.component.d.ts +25 -0
- package/lib/widget-library/one-of.component.d.ts +21 -0
- package/lib/widget-library/orderable.directive.d.ts +41 -0
- package/lib/widget-library/radios.component.d.ts +23 -0
- package/lib/widget-library/root.component.d.ts +17 -0
- package/lib/widget-library/section.component.d.ts +19 -0
- package/lib/widget-library/select-framework.component.d.ts +18 -0
- package/lib/widget-library/select-widget.component.d.ts +18 -0
- package/lib/widget-library/select.component.d.ts +24 -0
- package/lib/widget-library/submit.component.d.ts +24 -0
- package/lib/widget-library/tab.component.d.ts +14 -0
- package/lib/widget-library/tabs.component.d.ts +20 -0
- package/lib/widget-library/template.component.d.ts +18 -0
- package/lib/widget-library/textarea.component.d.ts +21 -0
- package/lib/widget-library/widget-library.module.d.ts +31 -0
- package/lib/widget-library/widget-library.service.d.ts +22 -0
- package/package.json +64 -53
- package/{src/public_api.ts → public_api.d.ts} +9 -21
- package/karma.conf.js +0 -46
- package/ng-package.json +0 -11
- package/src/lib/framework-library/framework-library.service.ts +0 -195
- package/src/lib/framework-library/framework.ts +0 -11
- package/src/lib/framework-library/no-framework.component.html +0 -2
- package/src/lib/framework-library/no-framework.component.ts +0 -11
- package/src/lib/framework-library/no-framework.module.ts +0 -18
- package/src/lib/framework-library/no.framework.ts +0 -11
- package/src/lib/json-schema-form.component.html +0 -7
- package/src/lib/json-schema-form.component.ts +0 -809
- package/src/lib/json-schema-form.module.ts +0 -17
- package/src/lib/json-schema-form.service.ts +0 -907
- package/src/lib/locale/de-validation-messages.ts +0 -58
- package/src/lib/locale/en-validation-messages.ts +0 -58
- package/src/lib/locale/es-validation-messages.ts +0 -55
- package/src/lib/locale/fr-validation-messages.ts +0 -58
- package/src/lib/locale/it-validation-messages.ts +0 -58
- package/src/lib/locale/pt-validation-messages.ts +0 -58
- package/src/lib/locale/zh-validation-messages.ts +0 -58
- package/src/lib/locale-dates/en-US.ts +0 -5
- package/src/lib/shared/convert-schema-to-draft6.function.ts +0 -321
- package/src/lib/shared/form-group.functions.ts +0 -522
- package/src/lib/shared/format-regex.constants.ts +0 -73
- package/src/lib/shared/index.ts +0 -40
- package/src/lib/shared/json-schema.functions.ts +0 -788
- package/src/lib/shared/json.validators.ts +0 -878
- package/src/lib/shared/jsonpointer.functions.ts +0 -1012
- package/src/lib/shared/jspointer.functions.json.spec.ts +0 -103
- package/src/lib/shared/layout.functions.ts +0 -1233
- package/src/lib/shared/merge-schemas.function.ts +0 -329
- package/src/lib/shared/utility.functions.ts +0 -373
- package/src/lib/shared/validator.functions.spec.ts +0 -55
- package/src/lib/widget-library/add-reference.component.ts +0 -59
- package/src/lib/widget-library/button.component.ts +0 -54
- package/src/lib/widget-library/checkbox.component.ts +0 -74
- package/src/lib/widget-library/checkboxes.component.ts +0 -104
- package/src/lib/widget-library/file.component.ts +0 -36
- package/src/lib/widget-library/hidden.component.ts +0 -39
- package/src/lib/widget-library/input.component.ts +0 -76
- package/src/lib/widget-library/message.component.ts +0 -29
- package/src/lib/widget-library/none.component.ts +0 -12
- package/src/lib/widget-library/number.component.ts +0 -79
- package/src/lib/widget-library/one-of.component.ts +0 -36
- package/src/lib/widget-library/orderable.directive.ts +0 -130
- package/src/lib/widget-library/radios.component.ts +0 -101
- package/src/lib/widget-library/root.component.ts +0 -78
- package/src/lib/widget-library/section.component.ts +0 -133
- package/src/lib/widget-library/select-framework.component.ts +0 -50
- package/src/lib/widget-library/select-widget.component.ts +0 -46
- package/src/lib/widget-library/select.component.ts +0 -96
- package/src/lib/widget-library/submit.component.ts +0 -68
- package/src/lib/widget-library/tab.component.ts +0 -29
- package/src/lib/widget-library/tabs.component.ts +0 -83
- package/src/lib/widget-library/template.component.ts +0 -52
- package/src/lib/widget-library/textarea.component.ts +0 -68
- package/src/lib/widget-library/widget-library.module.ts +0 -13
- package/src/lib/widget-library/widget-library.service.ts +0 -234
- package/src/test.ts +0 -18
- package/tsconfig.lib.json +0 -25
- package/tsconfig.lib.prod.json +0 -9
- package/tsconfig.spec.json +0 -17
- package/tslint.json +0 -11
|
@@ -1,809 +0,0 @@
|
|
|
1
|
-
import cloneDeep from 'lodash/cloneDeep';
|
|
2
|
-
import isEqual from 'lodash/isEqual';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
ChangeDetectionStrategy,
|
|
6
|
-
ChangeDetectorRef,
|
|
7
|
-
Component,
|
|
8
|
-
EventEmitter,
|
|
9
|
-
forwardRef,
|
|
10
|
-
Input,
|
|
11
|
-
OnChanges,
|
|
12
|
-
OnDestroy,
|
|
13
|
-
OnInit,
|
|
14
|
-
Output,
|
|
15
|
-
SimpleChanges,
|
|
16
|
-
} from '@angular/core';
|
|
17
|
-
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
18
|
-
import { Subject, Subscription } from 'rxjs';
|
|
19
|
-
import { takeUntil } from 'rxjs/operators';
|
|
20
|
-
import { FrameworkLibraryService } from './framework-library/framework-library.service';
|
|
21
|
-
import { JsonSchemaFormService } from './json-schema-form.service';
|
|
22
|
-
import { convertSchemaToDraft6 } from './shared/convert-schema-to-draft6.function';
|
|
23
|
-
import { resolveSchemaReferences } from './shared/json-schema.functions';
|
|
24
|
-
import { JsonPointer } from './shared/jsonpointer.functions';
|
|
25
|
-
import { forEach, hasOwn } from './shared/utility.functions';
|
|
26
|
-
import {
|
|
27
|
-
hasValue,
|
|
28
|
-
inArray,
|
|
29
|
-
isArray,
|
|
30
|
-
isEmpty,
|
|
31
|
-
isObject
|
|
32
|
-
} from './shared/validator.functions';
|
|
33
|
-
import { WidgetLibraryService } from './widget-library/widget-library.service';
|
|
34
|
-
|
|
35
|
-
export const JSON_SCHEMA_FORM_VALUE_ACCESSOR: any = {
|
|
36
|
-
provide: NG_VALUE_ACCESSOR,
|
|
37
|
-
useExisting: forwardRef(() => JsonSchemaFormComponent),
|
|
38
|
-
multi: true,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* @module 'JsonSchemaFormComponent' - Angular JSON Schema Form
|
|
43
|
-
*
|
|
44
|
-
* Root module of the Angular JSON Schema Form client-side library,
|
|
45
|
-
* an Angular library which generates an HTML form from a JSON schema
|
|
46
|
-
* structured data model and/or a JSON Schema Form layout description.
|
|
47
|
-
*
|
|
48
|
-
* This library also validates input data by the user, using both validators on
|
|
49
|
-
* individual controls to provide real-time feedback while the user is filling
|
|
50
|
-
* out the form, and then validating the entire input against the schema when
|
|
51
|
-
* the form is submitted to make sure the returned JSON data object is valid.
|
|
52
|
-
*
|
|
53
|
-
* This library is similar to, and mostly API compatible with:
|
|
54
|
-
*
|
|
55
|
-
* - JSON Schema Form's Angular Schema Form library for AngularJs
|
|
56
|
-
* http://schemaform.io
|
|
57
|
-
* http://schemaform.io/examples/bootstrap-example.html (examples)
|
|
58
|
-
*
|
|
59
|
-
* - Mozilla's react-jsonschema-form library for React
|
|
60
|
-
* https://github.com/mozilla-services/react-jsonschema-form
|
|
61
|
-
* https://mozilla-services.github.io/react-jsonschema-form (examples)
|
|
62
|
-
*
|
|
63
|
-
* - Joshfire's JSON Form library for jQuery
|
|
64
|
-
* https://github.com/joshfire/jsonform
|
|
65
|
-
* http://ulion.github.io/jsonform/playground (examples)
|
|
66
|
-
*
|
|
67
|
-
* This library depends on:
|
|
68
|
-
* - Angular (obviously) https://angular.io
|
|
69
|
-
* - lodash, JavaScript utility library https://github.com/lodash/lodash
|
|
70
|
-
* - ajv, Another JSON Schema validator https://github.com/epoberezkin/ajv
|
|
71
|
-
*
|
|
72
|
-
* In addition, the Example Playground also depends on:
|
|
73
|
-
* - brace, Browserified Ace editor http://thlorenz.github.io/brace
|
|
74
|
-
*/
|
|
75
|
-
@Component({
|
|
76
|
-
// tslint:disable-next-line:component-selector
|
|
77
|
-
selector: 'json-schema-form',
|
|
78
|
-
templateUrl: './json-schema-form.component.html',
|
|
79
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
80
|
-
// Adding 'JsonSchemaFormService' here, instead of in the module,
|
|
81
|
-
// creates a separate instance of the service for each component
|
|
82
|
-
providers: [ JsonSchemaFormService, JSON_SCHEMA_FORM_VALUE_ACCESSOR ],
|
|
83
|
-
})
|
|
84
|
-
export class JsonSchemaFormComponent implements ControlValueAccessor, OnChanges, OnInit,OnDestroy {
|
|
85
|
-
// TODO: quickfix to avoid subscribing twice to the same emitters
|
|
86
|
-
private unsubscribeOnActivateForm$ = new Subject<void>();
|
|
87
|
-
|
|
88
|
-
debugOutput: any; // Debug information, if requested
|
|
89
|
-
formValueSubscription: any = null;
|
|
90
|
-
formInitialized = false;
|
|
91
|
-
objectWrap = false; // Is non-object input schema wrapped in an object?
|
|
92
|
-
|
|
93
|
-
formValuesInput: string; // Name of the input providing the form data
|
|
94
|
-
previousInputs: { // Previous input values, to detect which input triggers onChanges
|
|
95
|
-
schema: any, layout: any[], data: any, options: any, framework: any | string,
|
|
96
|
-
widgets: any, form: any, model: any, JSONSchema: any, UISchema: any,
|
|
97
|
-
formData: any, loadExternalAssets: boolean, debug: boolean,
|
|
98
|
-
} = {
|
|
99
|
-
schema: null, layout: null, data: null, options: null, framework: null,
|
|
100
|
-
widgets: null, form: null, model: null, JSONSchema: null, UISchema: null,
|
|
101
|
-
formData: null, loadExternalAssets: null, debug: null,
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// Recommended inputs
|
|
105
|
-
@Input() schema: any; // The JSON Schema
|
|
106
|
-
@Input() layout: any[]; // The form layout
|
|
107
|
-
@Input() data: any; // The form data
|
|
108
|
-
@Input() options: any; // The global form options
|
|
109
|
-
@Input() framework: any | string; // The framework to load
|
|
110
|
-
@Input() widgets: any; // Any custom widgets to load
|
|
111
|
-
|
|
112
|
-
// Alternate combined single input
|
|
113
|
-
@Input() form: any; // For testing, and JSON Schema Form API compatibility
|
|
114
|
-
|
|
115
|
-
// Angular Schema Form API compatibility input
|
|
116
|
-
@Input() model: any; // Alternate input for form data
|
|
117
|
-
|
|
118
|
-
// React JSON Schema Form API compatibility inputs
|
|
119
|
-
@Input() JSONSchema: any; // Alternate input for JSON Schema
|
|
120
|
-
@Input() UISchema: any; // UI schema - alternate form layout format
|
|
121
|
-
@Input() formData: any; // Alternate input for form data
|
|
122
|
-
|
|
123
|
-
@Input() ngModel: any; // Alternate input for Angular forms
|
|
124
|
-
|
|
125
|
-
@Input() language: string; // Language
|
|
126
|
-
|
|
127
|
-
// Development inputs, for testing and debugging
|
|
128
|
-
@Input() loadExternalAssets: boolean; // Load external framework assets?
|
|
129
|
-
@Input() debug: boolean; // Show debug information?
|
|
130
|
-
|
|
131
|
-
@Input() theme: string; // Theme
|
|
132
|
-
|
|
133
|
-
@Input()
|
|
134
|
-
get value(): any {
|
|
135
|
-
return this.objectWrap ? this.jsf.data['1'] : this.jsf.data;
|
|
136
|
-
}
|
|
137
|
-
set value(value: any) {
|
|
138
|
-
this.setFormValues(value, false);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Outputs
|
|
142
|
-
@Output() onChanges = new EventEmitter<any>(); // Live unvalidated internal form data
|
|
143
|
-
@Output() onSubmit = new EventEmitter<any>(); // Complete validated form data
|
|
144
|
-
@Output() isValid = new EventEmitter<boolean>(); // Is current data valid?
|
|
145
|
-
@Output() validationErrors = new EventEmitter<any>(); // Validation errors (if any)
|
|
146
|
-
@Output() formSchema = new EventEmitter<any>(); // Final schema used to create form
|
|
147
|
-
@Output() formLayout = new EventEmitter<any>(); // Final layout used to create form
|
|
148
|
-
|
|
149
|
-
// Outputs for possible 2-way data binding
|
|
150
|
-
// Only the one input providing the initial form data will be bound.
|
|
151
|
-
// If there is no inital data, input '{}' to activate 2-way data binding.
|
|
152
|
-
// There is no 2-way binding if inital data is combined inside the 'form' input.
|
|
153
|
-
@Output() dataChange = new EventEmitter<any>();
|
|
154
|
-
@Output() modelChange = new EventEmitter<any>();
|
|
155
|
-
@Output() formDataChange = new EventEmitter<any>();
|
|
156
|
-
@Output() ngModelChange = new EventEmitter<any>();
|
|
157
|
-
|
|
158
|
-
onChange: Function;
|
|
159
|
-
onTouched: Function;
|
|
160
|
-
|
|
161
|
-
//TODO-review,maybe use takeUntilDestroyed rxjs op
|
|
162
|
-
dataChangesSubs:Subscription;
|
|
163
|
-
statusChangesSubs:Subscription;
|
|
164
|
-
isValidChangesSubs:Subscription;
|
|
165
|
-
validationErrorChangesSubs:Subscription;
|
|
166
|
-
|
|
167
|
-
constructor(
|
|
168
|
-
private changeDetector: ChangeDetectorRef,
|
|
169
|
-
private frameworkLibrary: FrameworkLibraryService,
|
|
170
|
-
private widgetLibrary: WidgetLibraryService,
|
|
171
|
-
public jsf: JsonSchemaFormService,
|
|
172
|
-
) { }
|
|
173
|
-
ngOnDestroy(): void {
|
|
174
|
-
this.dataChangesSubs?.unsubscribe();
|
|
175
|
-
this.statusChangesSubs?.unsubscribe();
|
|
176
|
-
this.isValidChangesSubs?.unsubscribe();
|
|
177
|
-
this.validationErrorChangesSubs?.unsubscribe();
|
|
178
|
-
this.dataChangesSubs=null;
|
|
179
|
-
this.statusChangesSubs=null;
|
|
180
|
-
this.isValidChangesSubs=null;
|
|
181
|
-
this.validationErrorChangesSubs=null;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
private resetScriptsAndStyleSheets() {
|
|
185
|
-
document.querySelectorAll('.ajsf').forEach(element => element.remove());
|
|
186
|
-
}
|
|
187
|
-
private loadScripts(scriptList?:string[]) {
|
|
188
|
-
const scripts = scriptList||this.frameworkLibrary.getFrameworkScripts();
|
|
189
|
-
scripts.map(script => {
|
|
190
|
-
const scriptTag: HTMLScriptElement = document.createElement('script');
|
|
191
|
-
scriptTag.src = script;
|
|
192
|
-
scriptTag.type = 'text/javascript';
|
|
193
|
-
scriptTag.async = true;
|
|
194
|
-
scriptTag.setAttribute('class', 'ajsf');
|
|
195
|
-
document.getElementsByTagName('head')[0].appendChild(scriptTag);
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
private loadStyleSheets(styleList?:string[]) {
|
|
199
|
-
const stylesheets = styleList||this.frameworkLibrary.getFrameworkStylesheets();
|
|
200
|
-
stylesheets.map(stylesheet => {
|
|
201
|
-
const linkTag: HTMLLinkElement = document.createElement('link');
|
|
202
|
-
linkTag.rel = 'stylesheet';
|
|
203
|
-
linkTag.href = stylesheet;
|
|
204
|
-
linkTag.setAttribute('class', 'ajsf');
|
|
205
|
-
document.getElementsByTagName('head')[0].appendChild(linkTag);
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
private loadAssets() {
|
|
209
|
-
this.frameworkLibrary.getFrameworkAssetConfig().then(assetCfg=>{
|
|
210
|
-
this.resetScriptsAndStyleSheets();
|
|
211
|
-
this.loadScripts(assetCfg.scripts);
|
|
212
|
-
this.loadStyleSheets(assetCfg.stylesheets);
|
|
213
|
-
}).catch(err=>{
|
|
214
|
-
console.log(err);
|
|
215
|
-
this.resetScriptsAndStyleSheets();
|
|
216
|
-
this.loadScripts();
|
|
217
|
-
this.loadStyleSheets();
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
ngOnInit() {
|
|
222
|
-
this.updateForm();
|
|
223
|
-
this.loadAssets();
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
ngOnChanges(changes: SimpleChanges) {
|
|
227
|
-
this.updateForm();
|
|
228
|
-
// Check if there's changes in Framework then load assets if that's the
|
|
229
|
-
if (changes.framework) {
|
|
230
|
-
if (!changes.framework.isFirstChange() &&
|
|
231
|
-
(changes.framework.previousValue !== changes.framework.currentValue)) {
|
|
232
|
-
this.loadAssets();
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
writeValue(value: any) {
|
|
238
|
-
this.setFormValues(value, false);
|
|
239
|
-
if (!this.formValuesInput) { this.formValuesInput = 'ngModel'; }
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
registerOnChange(fn: Function) {
|
|
243
|
-
this.onChange = fn;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
registerOnTouched(fn: Function) {
|
|
247
|
-
this.onTouched = fn;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
//see note
|
|
251
|
-
//https://angular.io/guide/update-to-version-15#v15-bc-06
|
|
252
|
-
setDisabledState(isDisabled: boolean) {
|
|
253
|
-
if (this.jsf.formOptions.formDisabled !== !!isDisabled) {
|
|
254
|
-
this.jsf.formOptions.formDisabled = !!isDisabled;
|
|
255
|
-
this.initializeForm();
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
updateForm() {
|
|
260
|
-
let changedData;
|
|
261
|
-
if (!this.formInitialized || !this.formValuesInput ||
|
|
262
|
-
(this.language && this.language !== this.jsf.language)
|
|
263
|
-
|
|
264
|
-
) {
|
|
265
|
-
this.initializeForm();
|
|
266
|
-
} else {
|
|
267
|
-
if (this.language && this.language !== this.jsf.language) {
|
|
268
|
-
this.jsf.setLanguage(this.language);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Get names of changed inputs
|
|
272
|
-
let changedInput = Object.keys(this.previousInputs)
|
|
273
|
-
.filter(input => this.previousInputs[input] !== this[input]);
|
|
274
|
-
let resetFirst = true;
|
|
275
|
-
if (changedInput.length === 1 && changedInput[0] === 'form' &&
|
|
276
|
-
this.formValuesInput.startsWith('form.')
|
|
277
|
-
) {
|
|
278
|
-
// If only 'form' input changed, get names of changed keys
|
|
279
|
-
changedInput = Object.keys(this.previousInputs.form || {})
|
|
280
|
-
.filter(key => !isEqual(this.previousInputs.form[key], this.form[key]))
|
|
281
|
-
.map(key => `form.${key}`);
|
|
282
|
-
resetFirst = false;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// If only input values have changed, update the form values
|
|
286
|
-
if (changedInput.length === 1 && changedInput[0] === this.formValuesInput) {
|
|
287
|
-
if (this.formValuesInput.indexOf('.') === -1) {
|
|
288
|
-
changedData=this[this.formValuesInput];
|
|
289
|
-
this.setFormValues(changedData, resetFirst);
|
|
290
|
-
} else {
|
|
291
|
-
const [input, key] = this.formValuesInput.split('.');
|
|
292
|
-
changedData=this[input][key];
|
|
293
|
-
this.setFormValues(changedData, resetFirst);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// If anything else has changed, re-render the entire form
|
|
297
|
-
} else if (changedInput.length) {
|
|
298
|
-
this.initializeForm(changedData);
|
|
299
|
-
if (this.onChange) { this.onChange(this.jsf.formValues); }
|
|
300
|
-
if (this.onTouched) { this.onTouched(this.jsf.formValues); }
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
//set framework theme
|
|
304
|
-
if (this.theme && this.theme !== this.frameworkLibrary.getActiveTheme()?.name) {
|
|
305
|
-
this.frameworkLibrary.requestThemeChange(this.theme);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Update previous inputs
|
|
309
|
-
Object.keys(this.previousInputs)
|
|
310
|
-
.filter(input => this.previousInputs[input] !== this[input])
|
|
311
|
-
.forEach(input => this.previousInputs[input] = this[input]);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
setFormValues(formValues: any, resetFirst = true) {
|
|
316
|
-
if (formValues) {
|
|
317
|
-
const newFormValues = this.objectWrap ? formValues['1'] : formValues;
|
|
318
|
-
if (!this.jsf.formGroup) {
|
|
319
|
-
this.jsf.formValues = formValues;
|
|
320
|
-
this.activateForm();
|
|
321
|
-
} else if (resetFirst) {//changed to avoid reset events
|
|
322
|
-
this.jsf.formGroup.reset({},{emitEvent:false});
|
|
323
|
-
}
|
|
324
|
-
if (this.jsf.formGroup) {//changed to avoid reset events
|
|
325
|
-
this.jsf.formGroup.patchValue(newFormValues,{emitEvent:false});
|
|
326
|
-
}
|
|
327
|
-
if (this.onChange) { this.onChange(newFormValues); }
|
|
328
|
-
if (this.onTouched) { this.onTouched(newFormValues); }
|
|
329
|
-
} else {
|
|
330
|
-
this.jsf.formGroup.reset();
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
submitForm() {
|
|
335
|
-
const validData = this.jsf.validData;
|
|
336
|
-
this.onSubmit.emit(this.objectWrap ? validData['1'] : validData);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* 'initializeForm' function
|
|
341
|
-
*
|
|
342
|
-
* - Update 'schema', 'layout', and 'formValues', from inputs.
|
|
343
|
-
*
|
|
344
|
-
* - Create 'schemaRefLibrary' and 'schemaRecursiveRefMap'
|
|
345
|
-
* to resolve schema $ref links, including recursive $ref links.
|
|
346
|
-
*
|
|
347
|
-
* - Create 'dataRecursiveRefMap' to resolve recursive links in data
|
|
348
|
-
* and corectly set output formats for recursively nested values.
|
|
349
|
-
*
|
|
350
|
-
* - Create 'layoutRefLibrary' and 'templateRefLibrary' to store
|
|
351
|
-
* new layout nodes and formGroup elements to use when dynamically
|
|
352
|
-
* adding form components to arrays and recursive $ref points.
|
|
353
|
-
*
|
|
354
|
-
* - Create 'dataMap' to map the data to the schema and template.
|
|
355
|
-
*
|
|
356
|
-
* - Create the master 'formGroupTemplate' then from it 'formGroup'
|
|
357
|
-
* the Angular formGroup used to control the reactive form.
|
|
358
|
-
*/
|
|
359
|
-
initializeForm(initialData?:any) {
|
|
360
|
-
if (
|
|
361
|
-
this.schema || this.layout || this.data || this.form || this.model ||
|
|
362
|
-
this.JSONSchema || this.UISchema || this.formData || this.ngModel ||
|
|
363
|
-
this.jsf.data
|
|
364
|
-
) {
|
|
365
|
-
// Reset all form values to defaults
|
|
366
|
-
this.jsf.resetAllValues();
|
|
367
|
-
this.initializeOptions(); // Update options
|
|
368
|
-
this.initializeSchema(); // Update schema, schemaRefLibrary,
|
|
369
|
-
// schemaRecursiveRefMap, & dataRecursiveRefMap
|
|
370
|
-
this.initializeLayout(); // Update layout, layoutRefLibrary,
|
|
371
|
-
this.initializeData(); // Update formValues
|
|
372
|
-
if(initialData){
|
|
373
|
-
this.jsf.formValues=initialData;
|
|
374
|
-
}
|
|
375
|
-
this.activateForm(); // Update dataMap, templateRefLibrary,
|
|
376
|
-
// formGroupTemplate, formGroup
|
|
377
|
-
|
|
378
|
-
// Uncomment individual lines to output debugging information to console:
|
|
379
|
-
// (These always work.)
|
|
380
|
-
// console.log('loading form...');
|
|
381
|
-
// console.log('schema', this.jsf.schema);
|
|
382
|
-
// console.log('layout', this.jsf.layout);
|
|
383
|
-
// console.log('options', this.options);
|
|
384
|
-
// console.log('formValues', this.jsf.formValues);
|
|
385
|
-
// console.log('formGroupTemplate', this.jsf.formGroupTemplate);
|
|
386
|
-
// console.log('formGroup', this.jsf.formGroup);
|
|
387
|
-
// console.log('formGroup.value', this.jsf.formGroup.value);
|
|
388
|
-
// console.log('schemaRefLibrary', this.jsf.schemaRefLibrary);
|
|
389
|
-
// console.log('layoutRefLibrary', this.jsf.layoutRefLibrary);
|
|
390
|
-
// console.log('templateRefLibrary', this.jsf.templateRefLibrary);
|
|
391
|
-
// console.log('dataMap', this.jsf.dataMap);
|
|
392
|
-
// console.log('arrayMap', this.jsf.arrayMap);
|
|
393
|
-
// console.log('schemaRecursiveRefMap', this.jsf.schemaRecursiveRefMap);
|
|
394
|
-
// console.log('dataRecursiveRefMap', this.jsf.dataRecursiveRefMap);
|
|
395
|
-
|
|
396
|
-
// Uncomment individual lines to output debugging information to browser:
|
|
397
|
-
// (These only work if the 'debug' option has also been set to 'true'.)
|
|
398
|
-
if (this.debug || this.jsf.formOptions.debug) {
|
|
399
|
-
const vars: any[] = [];
|
|
400
|
-
// vars.push(this.jsf.schema);
|
|
401
|
-
// vars.push(this.jsf.layout);
|
|
402
|
-
// vars.push(this.options);
|
|
403
|
-
// vars.push(this.jsf.formValues);
|
|
404
|
-
// vars.push(this.jsf.formGroup.value);
|
|
405
|
-
// vars.push(this.jsf.formGroupTemplate);
|
|
406
|
-
// vars.push(this.jsf.formGroup);
|
|
407
|
-
// vars.push(this.jsf.schemaRefLibrary);
|
|
408
|
-
// vars.push(this.jsf.layoutRefLibrary);
|
|
409
|
-
// vars.push(this.jsf.templateRefLibrary);
|
|
410
|
-
// vars.push(this.jsf.dataMap);
|
|
411
|
-
// vars.push(this.jsf.arrayMap);
|
|
412
|
-
// vars.push(this.jsf.schemaRecursiveRefMap);
|
|
413
|
-
// vars.push(this.jsf.dataRecursiveRefMap);
|
|
414
|
-
this.debugOutput = vars.map(v => JSON.stringify(v, null, 2)).join('\n');
|
|
415
|
-
}
|
|
416
|
-
this.formInitialized = true;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* 'initializeOptions' function
|
|
422
|
-
*
|
|
423
|
-
* Initialize 'options' (global form options) and set framework
|
|
424
|
-
* Combine available inputs:
|
|
425
|
-
* 1. options - recommended
|
|
426
|
-
* 2. form.options - Single input style
|
|
427
|
-
*/
|
|
428
|
-
private initializeOptions() {
|
|
429
|
-
if (this.language && this.language !== this.jsf.language) {
|
|
430
|
-
this.jsf.setLanguage(this.language);
|
|
431
|
-
}
|
|
432
|
-
this.jsf.setOptions({ debug: !!this.debug });
|
|
433
|
-
let loadExternalAssets: boolean = this.loadExternalAssets || false;
|
|
434
|
-
let framework: any = this.framework || 'default';
|
|
435
|
-
if (isObject(this.options)) {
|
|
436
|
-
this.jsf.setOptions(this.options);
|
|
437
|
-
loadExternalAssets = this.options.loadExternalAssets || loadExternalAssets;
|
|
438
|
-
framework = this.options.framework || framework;
|
|
439
|
-
}
|
|
440
|
-
if (isObject(this.form) && isObject(this.form.options)) {
|
|
441
|
-
this.jsf.setOptions(this.form.options);
|
|
442
|
-
loadExternalAssets = this.form.options.loadExternalAssets || loadExternalAssets;
|
|
443
|
-
framework = this.form.options.framework || framework;
|
|
444
|
-
}
|
|
445
|
-
if (isObject(this.widgets)) {
|
|
446
|
-
this.jsf.setOptions({ widgets: this.widgets });
|
|
447
|
-
}
|
|
448
|
-
this.frameworkLibrary.setLoadExternalAssets(loadExternalAssets);
|
|
449
|
-
this.frameworkLibrary.setFramework(framework);
|
|
450
|
-
this.jsf.framework = this.frameworkLibrary.getFramework();
|
|
451
|
-
if (isObject(this.jsf.formOptions.widgets)) {
|
|
452
|
-
for (const widget of Object.keys(this.jsf.formOptions.widgets)) {
|
|
453
|
-
this.widgetLibrary.registerWidget(widget, this.jsf.formOptions.widgets[widget]);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
if (isObject(this.form) && isObject(this.form.tpldata)) {
|
|
457
|
-
this.jsf.setTpldata(this.form.tpldata);
|
|
458
|
-
}
|
|
459
|
-
if (this.theme) {
|
|
460
|
-
this.frameworkLibrary.requestThemeChange(this.theme);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
/**
|
|
466
|
-
* 'initializeSchema' function
|
|
467
|
-
*
|
|
468
|
-
* Initialize 'schema'
|
|
469
|
-
* Use first available input:
|
|
470
|
-
* 1. schema - recommended / Angular Schema Form style
|
|
471
|
-
* 2. form.schema - Single input / JSON Form style
|
|
472
|
-
* 3. JSONSchema - React JSON Schema Form style
|
|
473
|
-
* 4. form.JSONSchema - For testing single input React JSON Schema Forms
|
|
474
|
-
* 5. form - For testing single schema-only inputs
|
|
475
|
-
*
|
|
476
|
-
* ... if no schema input found, the 'activateForm' function, below,
|
|
477
|
-
* will make two additional attempts to build a schema
|
|
478
|
-
* 6. If layout input - build schema from layout
|
|
479
|
-
* 7. If data input - build schema from data
|
|
480
|
-
*/
|
|
481
|
-
private initializeSchema() {
|
|
482
|
-
|
|
483
|
-
// TODO: update to allow non-object schemas
|
|
484
|
-
|
|
485
|
-
if (isObject(this.schema)) {
|
|
486
|
-
this.jsf.AngularSchemaFormCompatibility = true;
|
|
487
|
-
this.jsf.schema = cloneDeep(this.schema);
|
|
488
|
-
} else if (hasOwn(this.form, 'schema') && isObject(this.form.schema)) {
|
|
489
|
-
this.jsf.schema = cloneDeep(this.form.schema);
|
|
490
|
-
} else if (isObject(this.JSONSchema)) {
|
|
491
|
-
this.jsf.ReactJsonSchemaFormCompatibility = true;
|
|
492
|
-
this.jsf.schema = cloneDeep(this.JSONSchema);
|
|
493
|
-
} else if (hasOwn(this.form, 'JSONSchema') && isObject(this.form.JSONSchema)) {
|
|
494
|
-
this.jsf.ReactJsonSchemaFormCompatibility = true;
|
|
495
|
-
this.jsf.schema = cloneDeep(this.form.JSONSchema);
|
|
496
|
-
} else if (hasOwn(this.form, 'properties') && isObject(this.form.properties)) {
|
|
497
|
-
this.jsf.schema = cloneDeep(this.form);
|
|
498
|
-
} else if (isObject(this.form)) {
|
|
499
|
-
// TODO: Handle other types of form input
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
if (!isEmpty(this.jsf.schema)) {
|
|
503
|
-
|
|
504
|
-
// If other types also allowed, render schema as an object
|
|
505
|
-
if (inArray('object', this.jsf.schema.type)) {
|
|
506
|
-
this.jsf.schema.type = 'object';
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
// Wrap non-object schemas in object.
|
|
510
|
-
if (hasOwn(this.jsf.schema, 'type') && this.jsf.schema.type !== 'object') {
|
|
511
|
-
this.jsf.schema = {
|
|
512
|
-
'type': 'object',
|
|
513
|
-
'properties': { 1: this.jsf.schema }
|
|
514
|
-
};
|
|
515
|
-
this.objectWrap = true;
|
|
516
|
-
} else if (!hasOwn(this.jsf.schema, 'type')) {
|
|
517
|
-
|
|
518
|
-
// Add type = 'object' if missing
|
|
519
|
-
if (isObject(this.jsf.schema.properties) ||
|
|
520
|
-
isObject(this.jsf.schema.patternProperties) ||
|
|
521
|
-
isObject(this.jsf.schema.additionalProperties)
|
|
522
|
-
) {
|
|
523
|
-
this.jsf.schema.type = 'object';
|
|
524
|
-
|
|
525
|
-
// Fix JSON schema shorthand (JSON Form style)
|
|
526
|
-
} else {
|
|
527
|
-
this.jsf.JsonFormCompatibility = true;
|
|
528
|
-
this.jsf.schema = {
|
|
529
|
-
'type': 'object',
|
|
530
|
-
'properties': this.jsf.schema
|
|
531
|
-
};
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// If needed, update JSON Schema to draft 6 format, including
|
|
536
|
-
// draft 3 (JSON Form style) and draft 4 (Angular Schema Form style)
|
|
537
|
-
this.jsf.schema = convertSchemaToDraft6(this.jsf.schema);
|
|
538
|
-
|
|
539
|
-
// Initialize ajv and compile schema
|
|
540
|
-
this.jsf.compileAjvSchema();
|
|
541
|
-
|
|
542
|
-
// Create schemaRefLibrary, schemaRecursiveRefMap, dataRecursiveRefMap, & arrayMap
|
|
543
|
-
this.jsf.schema = resolveSchemaReferences(
|
|
544
|
-
this.jsf.schema, this.jsf.schemaRefLibrary, this.jsf.schemaRecursiveRefMap,
|
|
545
|
-
this.jsf.dataRecursiveRefMap, this.jsf.arrayMap
|
|
546
|
-
);
|
|
547
|
-
if (hasOwn(this.jsf.schemaRefLibrary, '')) {
|
|
548
|
-
this.jsf.hasRootReference = true;
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
// TODO: (?) Resolve external $ref links
|
|
552
|
-
// // Create schemaRefLibrary & schemaRecursiveRefMap
|
|
553
|
-
// this.parser.bundle(this.schema)
|
|
554
|
-
// .then(schema => this.schema = resolveSchemaReferences(
|
|
555
|
-
// schema, this.jsf.schemaRefLibrary,
|
|
556
|
-
// this.jsf.schemaRecursiveRefMap, this.jsf.dataRecursiveRefMap
|
|
557
|
-
// ));
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
/**
|
|
562
|
-
* 'initializeData' function
|
|
563
|
-
*
|
|
564
|
-
* Initialize 'formValues'
|
|
565
|
-
* defulat or previously submitted values used to populate form
|
|
566
|
-
* Use first available input:
|
|
567
|
-
* 1. data - recommended
|
|
568
|
-
* 2. model - Angular Schema Form style
|
|
569
|
-
* 3. form.value - JSON Form style
|
|
570
|
-
* 4. form.data - Single input style
|
|
571
|
-
* 5. formData - React JSON Schema Form style
|
|
572
|
-
* 6. form.formData - For easier testing of React JSON Schema Forms
|
|
573
|
-
* 7. (none) no data - initialize data from schema and layout defaults only
|
|
574
|
-
*/
|
|
575
|
-
private initializeData() {
|
|
576
|
-
if (hasValue(this.data)) {
|
|
577
|
-
this.jsf.formValues = cloneDeep(this.data);
|
|
578
|
-
this.formValuesInput = 'data';
|
|
579
|
-
} else if (hasValue(this.model)) {
|
|
580
|
-
this.jsf.AngularSchemaFormCompatibility = true;
|
|
581
|
-
this.jsf.formValues = cloneDeep(this.model);
|
|
582
|
-
this.formValuesInput = 'model';
|
|
583
|
-
} else if (hasValue(this.ngModel)) {
|
|
584
|
-
this.jsf.AngularSchemaFormCompatibility = true;
|
|
585
|
-
this.jsf.formValues = cloneDeep(this.ngModel);
|
|
586
|
-
this.formValuesInput = 'ngModel';
|
|
587
|
-
} else if (isObject(this.form) && hasValue(this.form.value)) {
|
|
588
|
-
this.jsf.JsonFormCompatibility = true;
|
|
589
|
-
this.jsf.formValues = cloneDeep(this.form.value);
|
|
590
|
-
this.formValuesInput = 'form.value';
|
|
591
|
-
} else if (isObject(this.form) && hasValue(this.form.data)) {
|
|
592
|
-
this.jsf.formValues = cloneDeep(this.form.data);
|
|
593
|
-
this.formValuesInput = 'form.data';
|
|
594
|
-
} else if (hasValue(this.formData)) {
|
|
595
|
-
this.jsf.ReactJsonSchemaFormCompatibility = true;
|
|
596
|
-
this.formValuesInput = 'formData';
|
|
597
|
-
} else if (hasOwn(this.form, 'formData') && hasValue(this.form.formData)) {
|
|
598
|
-
this.jsf.ReactJsonSchemaFormCompatibility = true;
|
|
599
|
-
this.jsf.formValues = cloneDeep(this.form.formData);
|
|
600
|
-
this.formValuesInput = 'form.formData';
|
|
601
|
-
} else {
|
|
602
|
-
this.formValuesInput = "data";//null;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
/**
|
|
607
|
-
* 'initializeLayout' function
|
|
608
|
-
*
|
|
609
|
-
* Initialize 'layout'
|
|
610
|
-
* Use first available array input:
|
|
611
|
-
* 1. layout - recommended
|
|
612
|
-
* 2. form - Angular Schema Form style
|
|
613
|
-
* 3. form.form - JSON Form style
|
|
614
|
-
* 4. form.layout - Single input style
|
|
615
|
-
* 5. (none) no layout - set default layout instead
|
|
616
|
-
* (full layout will be built later from the schema)
|
|
617
|
-
*
|
|
618
|
-
* Also, if alternate layout formats are available,
|
|
619
|
-
* import from 'UISchema' or 'customFormItems'
|
|
620
|
-
* used for React JSON Schema Form and JSON Form API compatibility
|
|
621
|
-
* Use first available input:
|
|
622
|
-
* 1. UISchema - React JSON Schema Form style
|
|
623
|
-
* 2. form.UISchema - For testing single input React JSON Schema Forms
|
|
624
|
-
* 2. form.customFormItems - JSON Form style
|
|
625
|
-
* 3. (none) no input - don't import
|
|
626
|
-
*/
|
|
627
|
-
private initializeLayout() {
|
|
628
|
-
|
|
629
|
-
// Rename JSON Form-style 'options' lists to
|
|
630
|
-
// Angular Schema Form-style 'titleMap' lists.
|
|
631
|
-
const fixJsonFormOptions = (layout: any): any => {
|
|
632
|
-
if (isObject(layout) || isArray(layout)) {
|
|
633
|
-
forEach(layout, (value, key) => {
|
|
634
|
-
if (hasOwn(value, 'options') && isObject(value.options)) {
|
|
635
|
-
value.titleMap = value.options;
|
|
636
|
-
delete value.options;
|
|
637
|
-
}
|
|
638
|
-
}, 'top-down');
|
|
639
|
-
}
|
|
640
|
-
return layout;
|
|
641
|
-
};
|
|
642
|
-
|
|
643
|
-
// Check for layout inputs and, if found, initialize form layout
|
|
644
|
-
if (isArray(this.layout)) {
|
|
645
|
-
this.jsf.layout = cloneDeep(this.layout);
|
|
646
|
-
} else if (isArray(this.form)) {
|
|
647
|
-
this.jsf.AngularSchemaFormCompatibility = true;
|
|
648
|
-
this.jsf.layout = cloneDeep(this.form);
|
|
649
|
-
} else if (this.form && isArray(this.form.form)) {
|
|
650
|
-
this.jsf.JsonFormCompatibility = true;
|
|
651
|
-
this.jsf.layout = fixJsonFormOptions(cloneDeep(this.form.form));
|
|
652
|
-
} else if (this.form && isArray(this.form.layout)) {
|
|
653
|
-
this.jsf.layout = cloneDeep(this.form.layout);
|
|
654
|
-
} else {
|
|
655
|
-
this.jsf.layout = ['*'];
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
// Check for alternate layout inputs
|
|
659
|
-
let alternateLayout: any = null;
|
|
660
|
-
if (isObject(this.UISchema)) {
|
|
661
|
-
this.jsf.ReactJsonSchemaFormCompatibility = true;
|
|
662
|
-
alternateLayout = cloneDeep(this.UISchema);
|
|
663
|
-
} else if (hasOwn(this.form, 'UISchema')) {
|
|
664
|
-
this.jsf.ReactJsonSchemaFormCompatibility = true;
|
|
665
|
-
alternateLayout = cloneDeep(this.form.UISchema);
|
|
666
|
-
} else if (hasOwn(this.form, 'uiSchema')) {
|
|
667
|
-
this.jsf.ReactJsonSchemaFormCompatibility = true;
|
|
668
|
-
alternateLayout = cloneDeep(this.form.uiSchema);
|
|
669
|
-
} else if (hasOwn(this.form, 'customFormItems')) {
|
|
670
|
-
this.jsf.JsonFormCompatibility = true;
|
|
671
|
-
alternateLayout = fixJsonFormOptions(cloneDeep(this.form.customFormItems));
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
// if alternate layout found, copy alternate layout options into schema
|
|
675
|
-
if (alternateLayout) {
|
|
676
|
-
JsonPointer.forEachDeep(alternateLayout, (value, pointer) => {
|
|
677
|
-
const schemaPointer = pointer
|
|
678
|
-
.replace(/\//g, '/properties/')
|
|
679
|
-
.replace(/\/properties\/items\/properties\//g, '/items/properties/')
|
|
680
|
-
.replace(/\/properties\/titleMap\/properties\//g, '/titleMap/properties/');
|
|
681
|
-
if (hasValue(value) && hasValue(pointer)) {
|
|
682
|
-
let key = JsonPointer.toKey(pointer);
|
|
683
|
-
const groupPointer = (JsonPointer.parse(schemaPointer) || []).slice(0, -2);
|
|
684
|
-
let itemPointer: string | string[];
|
|
685
|
-
|
|
686
|
-
// If 'ui:order' object found, copy into object schema root
|
|
687
|
-
if (key.toLowerCase() === 'ui:order') {
|
|
688
|
-
itemPointer = [...groupPointer, 'ui:order'];
|
|
689
|
-
|
|
690
|
-
// Copy other alternate layout options to schema 'x-schema-form',
|
|
691
|
-
// (like Angular Schema Form options) and remove any 'ui:' prefixes
|
|
692
|
-
} else {
|
|
693
|
-
if (key.slice(0, 3).toLowerCase() === 'ui:') { key = key.slice(3); }
|
|
694
|
-
itemPointer = [...groupPointer, 'x-schema-form', key];
|
|
695
|
-
}
|
|
696
|
-
if (JsonPointer.has(this.jsf.schema, groupPointer) &&
|
|
697
|
-
!JsonPointer.has(this.jsf.schema, itemPointer)
|
|
698
|
-
) {
|
|
699
|
-
JsonPointer.set(this.jsf.schema, itemPointer, value);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
});
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
/**
|
|
707
|
-
* 'activateForm' function
|
|
708
|
-
*
|
|
709
|
-
* ...continued from 'initializeSchema' function, above
|
|
710
|
-
* If 'schema' has not been initialized (i.e. no schema input found)
|
|
711
|
-
* 6. If layout input - build schema from layout input
|
|
712
|
-
* 7. If data input - build schema from data input
|
|
713
|
-
*
|
|
714
|
-
* Create final layout,
|
|
715
|
-
* build the FormGroup template and the Angular FormGroup,
|
|
716
|
-
* subscribe to changes,
|
|
717
|
-
* and activate the form.
|
|
718
|
-
*/
|
|
719
|
-
private activateForm() {
|
|
720
|
-
this.unsubscribeOnActivateForm$.next();
|
|
721
|
-
// If 'schema' not initialized
|
|
722
|
-
if (isEmpty(this.jsf.schema)) {
|
|
723
|
-
|
|
724
|
-
// TODO: If full layout input (with no '*'), build schema from layout
|
|
725
|
-
// if (!this.jsf.layout.includes('*')) {
|
|
726
|
-
// this.jsf.buildSchemaFromLayout();
|
|
727
|
-
// } else
|
|
728
|
-
|
|
729
|
-
// If data input, build schema from data
|
|
730
|
-
if (!isEmpty(this.jsf.formValues)) {
|
|
731
|
-
this.jsf.buildSchemaFromData();
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
if (!isEmpty(this.jsf.schema)) {
|
|
736
|
-
|
|
737
|
-
// If not already initialized, initialize ajv and compile schema
|
|
738
|
-
this.jsf.compileAjvSchema();
|
|
739
|
-
|
|
740
|
-
// Update all layout elements, add values, widgets, and validators,
|
|
741
|
-
// replace any '*' with a layout built from all schema elements,
|
|
742
|
-
// and update the FormGroup template with any new validators
|
|
743
|
-
this.jsf.buildLayout(this.widgetLibrary);
|
|
744
|
-
|
|
745
|
-
// Build the Angular FormGroup template from the schema
|
|
746
|
-
this.jsf.buildFormGroupTemplate(this.jsf.formValues);
|
|
747
|
-
|
|
748
|
-
// Build the real Angular FormGroup from the FormGroup template
|
|
749
|
-
this.jsf.buildFormGroup();
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
if (this.jsf.formGroup) {
|
|
753
|
-
|
|
754
|
-
// Reset initial form values
|
|
755
|
-
if (!isEmpty(this.jsf.formValues) &&
|
|
756
|
-
this.jsf.formOptions.setSchemaDefaults !== true &&
|
|
757
|
-
this.jsf.formOptions.setLayoutDefaults !== true
|
|
758
|
-
) {
|
|
759
|
-
this.setFormValues(this.jsf.formValues);
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
// TODO: Figure out how to display calculated values without changing object data
|
|
763
|
-
// See http://ulion.github.io/jsonform/playground/?example=templating-values
|
|
764
|
-
// Calculate references to other fields
|
|
765
|
-
// if (!isEmpty(this.jsf.formGroup.value)) {
|
|
766
|
-
// forEach(this.jsf.formGroup.value, (value, key, object, rootObject) => {
|
|
767
|
-
// if (typeof value === 'string') {
|
|
768
|
-
// object[key] = this.jsf.parseText(value, value, rootObject, key);
|
|
769
|
-
// }
|
|
770
|
-
// }, 'top-down');
|
|
771
|
-
// }
|
|
772
|
-
|
|
773
|
-
// Subscribe to form changes to output live data, validation, and errors
|
|
774
|
-
this.dataChangesSubs=this.jsf.dataChanges.pipe(takeUntil(this.unsubscribeOnActivateForm$)).subscribe(data => {
|
|
775
|
-
this.onChanges.emit(this.objectWrap ? data['1'] : data);
|
|
776
|
-
if (this.formValuesInput && this.formValuesInput.indexOf('.') === -1) {
|
|
777
|
-
this[`${this.formValuesInput}Change`].emit(this.objectWrap ? data['1'] : data);
|
|
778
|
-
}
|
|
779
|
-
});
|
|
780
|
-
|
|
781
|
-
// Trigger change detection on statusChanges to show updated errors
|
|
782
|
-
this.statusChangesSubs= this.jsf.formGroup.statusChanges.pipe(takeUntil(this.unsubscribeOnActivateForm$)).subscribe(() => this.changeDetector.markForCheck());
|
|
783
|
-
this.isValidChangesSubs=this.jsf.isValidChanges.pipe(takeUntil(this.unsubscribeOnActivateForm$)).subscribe(isValid => this.isValid.emit(isValid));
|
|
784
|
-
this.validationErrorChangesSubs=this.jsf.validationErrorChanges.pipe(takeUntil(this.unsubscribeOnActivateForm$)).subscribe(err => this.validationErrors.emit(err));
|
|
785
|
-
|
|
786
|
-
// Output final schema, final layout, and initial data
|
|
787
|
-
this.formSchema.emit(this.jsf.schema);
|
|
788
|
-
this.formLayout.emit(this.jsf.layout);
|
|
789
|
-
this.onChanges.emit(this.objectWrap ? this.jsf.data['1'] : this.jsf.data);
|
|
790
|
-
|
|
791
|
-
// If validateOnRender, output initial validation and any errors
|
|
792
|
-
const validateOnRender =
|
|
793
|
-
JsonPointer.get(this.jsf, '/formOptions/validateOnRender');
|
|
794
|
-
if (validateOnRender) { // validateOnRender === 'auto' || true
|
|
795
|
-
const touchAll = (control) => {
|
|
796
|
-
if (validateOnRender === true || hasValue(control.value)) {
|
|
797
|
-
control.markAsTouched();
|
|
798
|
-
}
|
|
799
|
-
Object.keys(control.controls || {})
|
|
800
|
-
.forEach(key => touchAll(control.controls[key]));
|
|
801
|
-
};
|
|
802
|
-
touchAll(this.jsf.formGroup);
|
|
803
|
-
this.isValid.emit(this.jsf.isValid);
|
|
804
|
-
this.validationErrors.emit(this.jsf.ajvErrors);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
}
|