@bolttech/form-engine-core 1.0.0-beta.1 → 1.0.0-beta.10
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/index.esm.js +207 -94
- package/package.json +1 -1
- package/src/interfaces/schema.d.ts +1 -0
- package/src/managers/field.d.ts +32 -1
- package/src/managers/form.d.ts +51 -5
- package/src/types/form.d.ts +1 -0
package/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Subject, Subscription, combineLatest, startWith, groupBy, mergeMap, debounceTime, filter, map, distinctUntilKeyChanged, distinctUntilChanged, skip } from 'rxjs';
|
|
2
2
|
import creditCardType from 'credit-card-type';
|
|
3
|
-
import { isNumber as isNumber$1, isFunction, cloneDeep, isEqual, get, isNil, set } from 'lodash';
|
|
3
|
+
import { isNumber as isNumber$1, isFunction, cloneDeep, merge, isEqual, get, isNil, set } from 'lodash';
|
|
4
4
|
import { getCurrencySymbol } from '@gaignoux/currency';
|
|
5
5
|
|
|
6
6
|
var TMutationEnum;
|
|
@@ -2496,9 +2496,11 @@ class FormField {
|
|
|
2496
2496
|
fieldEventSubject$,
|
|
2497
2497
|
dataSubject$,
|
|
2498
2498
|
formValidNotification$,
|
|
2499
|
+
mountSubject$,
|
|
2499
2500
|
mapper,
|
|
2500
2501
|
getFormValues,
|
|
2501
|
-
submitEvent
|
|
2502
|
+
submitEvent,
|
|
2503
|
+
visibility
|
|
2502
2504
|
}) {
|
|
2503
2505
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
2504
2506
|
this.valueSubscription$ = new Subscription();
|
|
@@ -2534,11 +2536,12 @@ class FormField {
|
|
|
2534
2536
|
this.fieldEventSubject$ = fieldEventSubject$;
|
|
2535
2537
|
this.dataSubject$ = dataSubject$;
|
|
2536
2538
|
this.formValidNotification$ = formValidNotification$;
|
|
2537
|
-
this.
|
|
2539
|
+
this.mountSubject$ = mountSubject$;
|
|
2540
|
+
this._props = FormField.filterProps(cloneDeep(schemaComponent.props || {}));
|
|
2538
2541
|
this._metadata = '';
|
|
2539
2542
|
this.errorsString = '';
|
|
2540
2543
|
this.errorsList = [];
|
|
2541
|
-
this._visibility = true;
|
|
2544
|
+
this._visibility = typeof visibility === 'boolean' ? visibility : true;
|
|
2542
2545
|
this._api = {
|
|
2543
2546
|
default: {
|
|
2544
2547
|
response: ((_e = (_d = (_c = this.apiSchema) === null || _c === void 0 ? void 0 : _c.defaultConfig) === null || _d === void 0 ? void 0 : _d.config) === null || _e === void 0 ? void 0 : _e.fallbackValue) || '',
|
|
@@ -2554,35 +2557,37 @@ class FormField {
|
|
|
2554
2557
|
}, {})
|
|
2555
2558
|
};
|
|
2556
2559
|
this._errors = {};
|
|
2557
|
-
this._mounted =
|
|
2558
|
-
this._valid =
|
|
2560
|
+
this._mounted = false;
|
|
2561
|
+
this._valid = true;
|
|
2559
2562
|
this.initializeObservers();
|
|
2560
2563
|
}
|
|
2561
2564
|
/**
|
|
2562
2565
|
* method to initialize all recycled Subjects and initialize Observers on field instance creation or rerender
|
|
2566
|
+
* due to some visibility conditions unmounts the field from the adapter if they are children of it and avoid
|
|
2567
|
+
* emissions to unsubscribed fields
|
|
2563
2568
|
*/
|
|
2564
2569
|
initializeObservers() {
|
|
2565
2570
|
var _a;
|
|
2566
2571
|
if (!this.valueSubject$ || this.valueSubject$.closed) {
|
|
2567
|
-
this.valueSubject$ = new SafeSubject(() => this.
|
|
2572
|
+
this.valueSubject$ = new SafeSubject(() => this.mounted);
|
|
2568
2573
|
}
|
|
2569
2574
|
if (!this.errorSubject$ || this.errorSubject$.closed) {
|
|
2570
|
-
this.errorSubject$ = new SafeSubject(() => this.
|
|
2575
|
+
this.errorSubject$ = new SafeSubject(() => this.mounted);
|
|
2571
2576
|
}
|
|
2572
2577
|
if (!this.visibilitySubject$ || this.visibilitySubject$.closed) {
|
|
2573
|
-
this.visibilitySubject$ = new SafeSubject(() => this.
|
|
2578
|
+
this.visibilitySubject$ = new SafeSubject(() => this.mounted);
|
|
2574
2579
|
}
|
|
2575
2580
|
if (!this.apiSubject$ || this.apiSubject$.closed) {
|
|
2576
|
-
this.apiSubject$ = new SafeSubject(() => this.
|
|
2581
|
+
this.apiSubject$ = new SafeSubject(() => this.mounted);
|
|
2577
2582
|
}
|
|
2578
2583
|
if (!this.propsSubject$ || this.propsSubject$.closed) {
|
|
2579
|
-
this.propsSubject$ = new SafeSubject(() => this.
|
|
2584
|
+
this.propsSubject$ = new SafeSubject(() => this.mounted);
|
|
2580
2585
|
}
|
|
2581
2586
|
if (!this.fieldStateSubscription$ || this.fieldStateSubscription$.closed) {
|
|
2582
2587
|
this.fieldStateSubscription$ = new Subscription();
|
|
2583
2588
|
}
|
|
2584
2589
|
if (!this.apiEventQueueSubject$ || this.apiEventQueueSubject$.closed) {
|
|
2585
|
-
this.apiEventQueueSubject$ = new SafeSubject(() => this.
|
|
2590
|
+
this.apiEventQueueSubject$ = new SafeSubject(() => this.mounted);
|
|
2586
2591
|
}
|
|
2587
2592
|
this.fieldState$ = combineLatest({
|
|
2588
2593
|
visibility: this.visibilitySubject$.pipe(startWith(this._visibility)),
|
|
@@ -2611,8 +2616,9 @@ class FormField {
|
|
|
2611
2616
|
* @param {Record<string, unknown>} props - The new properties to be set.
|
|
2612
2617
|
*/
|
|
2613
2618
|
set props(props) {
|
|
2614
|
-
|
|
2615
|
-
this.
|
|
2619
|
+
const diffProps = merge(cloneDeep(this.props), props);
|
|
2620
|
+
if (typeof diffProps === 'undefined' || isEqual(diffProps, this.props)) return;
|
|
2621
|
+
this._props = diffProps;
|
|
2616
2622
|
this.propsSubject$.next(this.props);
|
|
2617
2623
|
this.templateSubject$.next({
|
|
2618
2624
|
scope: 'fields',
|
|
@@ -2620,6 +2626,28 @@ class FormField {
|
|
|
2620
2626
|
event: 'ON_PROPS'
|
|
2621
2627
|
});
|
|
2622
2628
|
}
|
|
2629
|
+
/**
|
|
2630
|
+
* Static function to remove templates form the component props that will be shown when
|
|
2631
|
+
* the field mounts and the template routine executes, to be used on the adapter
|
|
2632
|
+
*
|
|
2633
|
+
* @param {unknown} props - the properties from the adapter components.
|
|
2634
|
+
*/
|
|
2635
|
+
static filterProps(props) {
|
|
2636
|
+
if (Array.isArray(props)) {
|
|
2637
|
+
return props.filter(el => typeof el === 'string' && el.includes('${') ? false : true).map(el => FormField.filterProps(el));
|
|
2638
|
+
}
|
|
2639
|
+
if (typeof props === 'object' && props !== null) {
|
|
2640
|
+
return Object.keys(props).reduce((acc, curr) => {
|
|
2641
|
+
const propValue = props[curr];
|
|
2642
|
+
if (typeof propValue === 'string' && propValue.includes('${')) {
|
|
2643
|
+
return acc;
|
|
2644
|
+
}
|
|
2645
|
+
acc[curr] = FormField.filterProps(props[curr]);
|
|
2646
|
+
return acc;
|
|
2647
|
+
}, {});
|
|
2648
|
+
}
|
|
2649
|
+
return props;
|
|
2650
|
+
}
|
|
2623
2651
|
/**
|
|
2624
2652
|
* Retrieves the current state value of the form field.
|
|
2625
2653
|
*
|
|
@@ -2784,6 +2812,29 @@ class FormField {
|
|
|
2784
2812
|
event: 'ON_API_FIELD_RESPONSE'
|
|
2785
2813
|
});
|
|
2786
2814
|
}
|
|
2815
|
+
/**
|
|
2816
|
+
* Retrieves the mounted status of the field.
|
|
2817
|
+
*
|
|
2818
|
+
* @returns {boolean} - the mounted status of the field.
|
|
2819
|
+
*/
|
|
2820
|
+
get mounted() {
|
|
2821
|
+
return this._mounted;
|
|
2822
|
+
}
|
|
2823
|
+
/**
|
|
2824
|
+
* sets the mountedStatus and notifies the form that the field was mounted on the adapter
|
|
2825
|
+
* and it's ready to be handled by the form instance
|
|
2826
|
+
*
|
|
2827
|
+
* @param {boolean} mountedStatus - the mounted status to be set from the mountField function.
|
|
2828
|
+
*/
|
|
2829
|
+
set mounted(mountedStatus) {
|
|
2830
|
+
if (typeof mountedStatus === 'undefined' || mountedStatus === this.mounted) return;
|
|
2831
|
+
this._mounted = mountedStatus;
|
|
2832
|
+
this.initializeObservers();
|
|
2833
|
+
this.mountSubject$.next({
|
|
2834
|
+
key: this.name,
|
|
2835
|
+
status: this.mounted
|
|
2836
|
+
});
|
|
2837
|
+
}
|
|
2787
2838
|
/**
|
|
2788
2839
|
* Mounts the form field by initializing necessary subjects and combining their streams.
|
|
2789
2840
|
*
|
|
@@ -2796,10 +2847,15 @@ class FormField {
|
|
|
2796
2847
|
valueSubscription,
|
|
2797
2848
|
propsSubscription
|
|
2798
2849
|
}) {
|
|
2799
|
-
this.
|
|
2850
|
+
this.mounted = true;
|
|
2800
2851
|
this.subscribeValue(valueSubscription);
|
|
2801
2852
|
this.subscribeState(propsSubscription);
|
|
2802
|
-
this.
|
|
2853
|
+
this.valueSubject$.next(this.stateValue);
|
|
2854
|
+
this.propsSubject$.next(this.props);
|
|
2855
|
+
this.visibilitySubject$.next(this.visibility);
|
|
2856
|
+
this.setFieldValidity({
|
|
2857
|
+
event: 'ON_FIELD_MOUNT'
|
|
2858
|
+
});
|
|
2803
2859
|
}
|
|
2804
2860
|
/**
|
|
2805
2861
|
* Sets the value of the form field and emits associated events.
|
|
@@ -2809,7 +2865,7 @@ class FormField {
|
|
|
2809
2865
|
* @returns {void}
|
|
2810
2866
|
*/
|
|
2811
2867
|
emitValue(prop) {
|
|
2812
|
-
if (!this.visibility) return;
|
|
2868
|
+
if (!this.visibility || !this.mounted) return;
|
|
2813
2869
|
this.value = prop.value;
|
|
2814
2870
|
this.emitEvents({
|
|
2815
2871
|
event: prop.event
|
|
@@ -2831,13 +2887,13 @@ class FormField {
|
|
|
2831
2887
|
if (event === 'ON_FORM_SUBMIT') {
|
|
2832
2888
|
return this.submitEvent();
|
|
2833
2889
|
}
|
|
2834
|
-
this.setFieldValidity({
|
|
2835
|
-
event
|
|
2836
|
-
});
|
|
2837
2890
|
this.validateVisibility({
|
|
2838
2891
|
event,
|
|
2839
2892
|
key: this.name
|
|
2840
2893
|
});
|
|
2894
|
+
this.setFieldValidity({
|
|
2895
|
+
event
|
|
2896
|
+
});
|
|
2841
2897
|
this.resetValue({
|
|
2842
2898
|
event,
|
|
2843
2899
|
key: this.name
|
|
@@ -3037,7 +3093,7 @@ class FormField {
|
|
|
3037
3093
|
* @returns {void}
|
|
3038
3094
|
*/
|
|
3039
3095
|
destroyField() {
|
|
3040
|
-
this.
|
|
3096
|
+
this.mounted = false;
|
|
3041
3097
|
this.valueSubscription$.unsubscribe();
|
|
3042
3098
|
this.visibilitySubject$.unsubscribe();
|
|
3043
3099
|
this.fieldStateSubscription$.unsubscribe();
|
|
@@ -3100,13 +3156,12 @@ class FormCore {
|
|
|
3100
3156
|
this.fields = new Map();
|
|
3101
3157
|
this.action = entry.action || ((_a = entry.schema) === null || _a === void 0 ? void 0 : _a.action);
|
|
3102
3158
|
this.method = entry.method || ((_b = entry.schema) === null || _b === void 0 ? void 0 : _b.method);
|
|
3103
|
-
this._iVars = entry.iVars || ((_c = entry.schema) === null || _c === void 0 ? void 0 : _c.iVars) || {};
|
|
3104
3159
|
this.config = {
|
|
3105
|
-
defaultAPIdebounceTimeMS: Number((
|
|
3106
|
-
defaultStateRefreshTimeMS: Number((
|
|
3107
|
-
defaultLogVerbose: ((
|
|
3160
|
+
defaultAPIdebounceTimeMS: Number((_c = entry.config) === null || _c === void 0 ? void 0 : _c.defaultAPIdebounceTimeMS) ? Number((_d = entry.config) === null || _d === void 0 ? void 0 : _d.defaultAPIdebounceTimeMS) : DEFAULT_API_DEBOUNCE_TIME,
|
|
3161
|
+
defaultStateRefreshTimeMS: Number((_e = entry.config) === null || _e === void 0 ? void 0 : _e.defaultStateRefreshTimeMS) ? Number((_f = entry.config) === null || _f === void 0 ? void 0 : _f.defaultStateRefreshTimeMS) : DEFAULT_STATE_REFRESH_TIME,
|
|
3162
|
+
defaultLogVerbose: ((_g = entry.config) === null || _g === void 0 ? void 0 : _g.defaultLogVerbose) ? entry.config.defaultLogVerbose : DEFAULT_LOG_VERBOSE
|
|
3108
3163
|
};
|
|
3109
|
-
(
|
|
3164
|
+
(_h = entry.mappers) === null || _h === void 0 ? void 0 : _h.map(mapper => {
|
|
3110
3165
|
this.mappers.set(mapper.componentName, mapper);
|
|
3111
3166
|
});
|
|
3112
3167
|
this.schema && FormCore.checkIndexes(this.schema.components);
|
|
@@ -3117,40 +3172,77 @@ class FormCore {
|
|
|
3117
3172
|
this.mountSubject$ = new Subject();
|
|
3118
3173
|
this.formValidNotification$ = new Subject();
|
|
3119
3174
|
this.subscribedTemplates = [];
|
|
3120
|
-
this.schema && this.serializeStructure(this.schema.components);
|
|
3121
|
-
this.schema && this.subscribeTemplates();
|
|
3122
3175
|
this.templateSubscription$ = this.templateSubject$.subscribe(this.refreshTemplates.bind(this));
|
|
3123
|
-
this.
|
|
3124
|
-
|
|
3125
|
-
|
|
3176
|
+
this.mountSubject$.subscribe(this.mountActions.bind(this));
|
|
3177
|
+
this.initialValues = entry.initialValues || ((_j = entry.schema) === null || _j === void 0 ? void 0 : _j.initialValues);
|
|
3178
|
+
this.iVars = entry.iVars || ((_k = entry.schema) === null || _k === void 0 ? void 0 : _k.iVars) || {};
|
|
3179
|
+
}
|
|
3180
|
+
/**
|
|
3181
|
+
* mock function to simulate form mount onto the adapter
|
|
3182
|
+
*/
|
|
3183
|
+
generateFields() {
|
|
3184
|
+
this.schema && this.serializeStructure(this.schema.components);
|
|
3185
|
+
this.fields.forEach(field => {
|
|
3186
|
+
field.mountField({
|
|
3187
|
+
valueSubscription: () => null,
|
|
3188
|
+
propsSubscription: () => null
|
|
3189
|
+
});
|
|
3126
3190
|
});
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3191
|
+
}
|
|
3192
|
+
/**
|
|
3193
|
+
* callback function passed to field instance to notify field adapter mount status
|
|
3194
|
+
* once the field has all field instance properties set, this function will handle all
|
|
3195
|
+
* field routines
|
|
3196
|
+
*
|
|
3197
|
+
* @param { string } entry.key field unique identifier
|
|
3198
|
+
* @param { boolean } entry.status mount status notified from field
|
|
3199
|
+
*/
|
|
3200
|
+
mountActions({
|
|
3201
|
+
key,
|
|
3202
|
+
status
|
|
3203
|
+
}) {
|
|
3204
|
+
var _a;
|
|
3205
|
+
if (status) {
|
|
3206
|
+
const field = this.fields.get(key);
|
|
3207
|
+
if (!field) {
|
|
3208
|
+
/*
|
|
3209
|
+
@TODO check a better way to handle nested fields unmounted by visiblity conditions from a parent
|
|
3210
|
+
since they are dependent on adapter field recycling runtimes
|
|
3211
|
+
*/
|
|
3212
|
+
this.config.defaultLogVerbose && console.log(`field ${key} was mounted but since it's parent has some visibility condition the field was already removed`);
|
|
3213
|
+
return;
|
|
3140
3214
|
}
|
|
3215
|
+
this.subscribeTemplates();
|
|
3141
3216
|
this.refreshTemplates({
|
|
3142
3217
|
scope: 'fields',
|
|
3143
|
-
key,
|
|
3144
3218
|
event: 'ON_FIELDS'
|
|
3145
3219
|
});
|
|
3146
|
-
|
|
3147
|
-
|
|
3220
|
+
this.templateSubject$.next({
|
|
3221
|
+
scope: 'iVars',
|
|
3222
|
+
event: 'ON_IVARS'
|
|
3223
|
+
});
|
|
3224
|
+
if (!this.queuedInitialValues.has(key)) {
|
|
3225
|
+
const propValue = (_a = field === null || field === void 0 ? void 0 : field.props) === null || _a === void 0 ? void 0 : _a[(field === null || field === void 0 ? void 0 : field.valuePropName) || ''];
|
|
3226
|
+
!(field === null || field === void 0 ? void 0 : field.value) ? field.emitValue({
|
|
3227
|
+
value: typeof propValue === 'string' && !propValue.includes('${') ? propValue : '',
|
|
3228
|
+
event: 'ON_FIELD_MOUNT'
|
|
3229
|
+
}) : field.emitEvents({
|
|
3230
|
+
event: 'ON_FIELD_MOUNT'
|
|
3231
|
+
});
|
|
3232
|
+
}
|
|
3233
|
+
this.checkFieldEventQueues(key);
|
|
3234
|
+
}
|
|
3148
3235
|
}
|
|
3149
|
-
|
|
3236
|
+
/**
|
|
3237
|
+
* initialValues setter to handle field values set externally from the adapter
|
|
3238
|
+
*
|
|
3239
|
+
* @param { Record<string, unknown> | undefined } payload initialValues to set onto fields
|
|
3240
|
+
*/
|
|
3241
|
+
set initialValues(payload) {
|
|
3150
3242
|
if (payload) {
|
|
3151
3243
|
Object.keys(payload).forEach(key => {
|
|
3152
3244
|
const field = this.fields.get(key);
|
|
3153
|
-
if (!field || !(field === null || field === void 0 ? void 0 : field.visibility)) {
|
|
3245
|
+
if (!field || !(field === null || field === void 0 ? void 0 : field.visibility) || !(field === null || field === void 0 ? void 0 : field.mounted)) {
|
|
3154
3246
|
this.queuedInitialValues.set(key, payload === null || payload === void 0 ? void 0 : payload[key]);
|
|
3155
3247
|
} else {
|
|
3156
3248
|
field.emitValue({
|
|
@@ -3187,6 +3279,7 @@ class FormCore {
|
|
|
3187
3279
|
* @returns {boolean} True if the form is valid; otherwise, false.
|
|
3188
3280
|
*/
|
|
3189
3281
|
get isValid() {
|
|
3282
|
+
if (this.fields.size === 0) return false;
|
|
3190
3283
|
for (const [, field] of this.fields) {
|
|
3191
3284
|
if (!field.valid) return false;
|
|
3192
3285
|
}
|
|
@@ -3293,10 +3386,8 @@ class FormCore {
|
|
|
3293
3386
|
}
|
|
3294
3387
|
const fieldProp = field[property];
|
|
3295
3388
|
let propState;
|
|
3296
|
-
if (Array.isArray(fieldProp)) {
|
|
3297
|
-
propState =
|
|
3298
|
-
} else if (typeof fieldProp === 'object' && !isNil(fieldProp)) {
|
|
3299
|
-
propState = Object.assign({}, fieldProp);
|
|
3389
|
+
if (Array.isArray(fieldProp) || typeof fieldProp === 'object' && !isNil(fieldProp)) {
|
|
3390
|
+
propState = cloneDeep(fieldProp);
|
|
3300
3391
|
} else {
|
|
3301
3392
|
this.config.defaultLogVerbose && console.warn(`invalid template property, skipping evaluation of ${field.name} with ${fieldProp}`);
|
|
3302
3393
|
return;
|
|
@@ -3466,6 +3557,8 @@ class FormCore {
|
|
|
3466
3557
|
* @param {string} field field to check
|
|
3467
3558
|
*/
|
|
3468
3559
|
checkFieldEventQueues(field) {
|
|
3560
|
+
var _a;
|
|
3561
|
+
if (!((_a = this.fields.get(field)) === null || _a === void 0 ? void 0 : _a.mounted)) return;
|
|
3469
3562
|
if (this.queuedFieldVisibilityEvents.has(field)) {
|
|
3470
3563
|
this.setFieldVisibility(Object.assign({
|
|
3471
3564
|
field: field
|
|
@@ -3473,10 +3566,11 @@ class FormCore {
|
|
|
3473
3566
|
this.queuedFieldVisibilityEvents.delete(field);
|
|
3474
3567
|
}
|
|
3475
3568
|
if (this.queuedInitialValues.has(field)) {
|
|
3476
|
-
this.
|
|
3477
|
-
[field]: this.queuedInitialValues.get(field)
|
|
3478
|
-
});
|
|
3569
|
+
const value = this.queuedInitialValues.get(field);
|
|
3479
3570
|
this.queuedInitialValues.delete(field);
|
|
3571
|
+
this.initialValues = {
|
|
3572
|
+
[field]: value
|
|
3573
|
+
};
|
|
3480
3574
|
}
|
|
3481
3575
|
if (this.queuedFieldResetValuesEvents.has(field)) {
|
|
3482
3576
|
this.setResetFieldValue(Object.assign({
|
|
@@ -3506,14 +3600,16 @@ class FormCore {
|
|
|
3506
3600
|
showOnlyIfTrue
|
|
3507
3601
|
}) {
|
|
3508
3602
|
const fieldInstance = this.fields.get(field);
|
|
3509
|
-
if (!fieldInstance) {
|
|
3603
|
+
if (!fieldInstance || !fieldInstance.mounted) {
|
|
3510
3604
|
this.queuedFieldVisibilityEvents.set(field, {
|
|
3511
3605
|
hasError,
|
|
3512
3606
|
showOnlyIfTrue
|
|
3513
3607
|
});
|
|
3514
3608
|
} else {
|
|
3609
|
+
const currentVisibility = fieldInstance.visibility;
|
|
3515
3610
|
const visibility = showOnlyIfTrue ? hasError : !hasError;
|
|
3516
3611
|
fieldInstance.visibility = visibility;
|
|
3612
|
+
if (currentVisibility === visibility) return;
|
|
3517
3613
|
/**
|
|
3518
3614
|
* I was sure I would not require to gambiarra, but..
|
|
3519
3615
|
* in order to ignore an hidden value on a form submit
|
|
@@ -3585,12 +3681,12 @@ class FormCore {
|
|
|
3585
3681
|
key,
|
|
3586
3682
|
value
|
|
3587
3683
|
}) {
|
|
3588
|
-
|
|
3684
|
+
const field = this.fields.get(key);
|
|
3685
|
+
if (!field || !(field === null || field === void 0 ? void 0 : field.mounted)) {
|
|
3589
3686
|
this.queuedFieldResetValuesEvents.set(key, {
|
|
3590
3687
|
value
|
|
3591
3688
|
});
|
|
3592
3689
|
} else {
|
|
3593
|
-
const field = this.fields.get(key);
|
|
3594
3690
|
field.emitValue({
|
|
3595
3691
|
value: value,
|
|
3596
3692
|
event: 'ON_FIELD_CLEARED'
|
|
@@ -3656,7 +3752,8 @@ class FormCore {
|
|
|
3656
3752
|
path,
|
|
3657
3753
|
value
|
|
3658
3754
|
}) {
|
|
3659
|
-
|
|
3755
|
+
const field = this.fields.get(key);
|
|
3756
|
+
if (!field || field.mounted) {
|
|
3660
3757
|
this.queuedFieldResetPropertyEvents.set(key, {
|
|
3661
3758
|
property,
|
|
3662
3759
|
path,
|
|
@@ -3720,7 +3817,7 @@ class FormCore {
|
|
|
3720
3817
|
fieldSchema,
|
|
3721
3818
|
mapperElement
|
|
3722
3819
|
}) {
|
|
3723
|
-
var _a
|
|
3820
|
+
var _a;
|
|
3724
3821
|
if (this.fields.has(fieldSchema.name)) {
|
|
3725
3822
|
throw new Error(`field name ${fieldSchema.name} already defined`);
|
|
3726
3823
|
}
|
|
@@ -3738,24 +3835,17 @@ class FormCore {
|
|
|
3738
3835
|
fieldEventSubject$: this.fieldEventSubject$,
|
|
3739
3836
|
dataSubject$: this.dataSubject$,
|
|
3740
3837
|
formValidNotification$: this.formValidNotification$,
|
|
3838
|
+
mountSubject$: this.mountSubject$,
|
|
3741
3839
|
config: this.config,
|
|
3742
|
-
submitEvent: this.submit.bind(this)
|
|
3840
|
+
submitEvent: this.submit.bind(this),
|
|
3841
|
+
visibility: fieldSchema.visibility
|
|
3743
3842
|
}));
|
|
3744
|
-
this.subscribeTemplates();
|
|
3745
|
-
this.refreshTemplates({
|
|
3746
|
-
scope: 'fields',
|
|
3747
|
-
event: 'ON_FIELDS'
|
|
3748
|
-
});
|
|
3749
|
-
if (!this.queuedInitialValues.has(fieldSchema.name)) {
|
|
3750
|
-
const field = this.fields.get(fieldSchema.name);
|
|
3751
|
-
const propValue = (_b = field === null || field === void 0 ? void 0 : field.props) === null || _b === void 0 ? void 0 : _b[(field === null || field === void 0 ? void 0 : field.valuePropName) || ''];
|
|
3752
|
-
!(field === null || field === void 0 ? void 0 : field.value) && (field === null || field === void 0 ? void 0 : field.emitValue({
|
|
3753
|
-
value: typeof propValue === 'string' && !propValue.includes('${') ? propValue : '',
|
|
3754
|
-
event: 'ON_FIELD_MOUNT'
|
|
3755
|
-
}));
|
|
3756
|
-
}
|
|
3757
|
-
this.checkFieldEventQueues(fieldSchema.name);
|
|
3758
3843
|
}
|
|
3844
|
+
/**
|
|
3845
|
+
* function to be called from the adapter to remove a field when a field is removed from it
|
|
3846
|
+
*
|
|
3847
|
+
* @param {{ key: string }} entry.key
|
|
3848
|
+
*/
|
|
3759
3849
|
removeField({
|
|
3760
3850
|
key
|
|
3761
3851
|
}) {
|
|
@@ -3800,9 +3890,11 @@ class FormCore {
|
|
|
3800
3890
|
fieldEventSubject$: this.fieldEventSubject$,
|
|
3801
3891
|
dataSubject$: this.dataSubject$,
|
|
3802
3892
|
formValidNotification$: this.formValidNotification$,
|
|
3893
|
+
mountSubject$: this.mountSubject$,
|
|
3803
3894
|
config: this.config,
|
|
3804
3895
|
getFormValues: this.getFormValues.bind(this),
|
|
3805
|
-
submitEvent: this.submit.bind(this)
|
|
3896
|
+
submitEvent: this.submit.bind(this),
|
|
3897
|
+
visibility: structElement.visibility
|
|
3806
3898
|
}));
|
|
3807
3899
|
} else {
|
|
3808
3900
|
currField.children = ((_b = structElement === null || structElement === void 0 ? void 0 : structElement.children) === null || _b === void 0 ? void 0 : _b.map(el => el.name)) || (currField === null || currField === void 0 ? void 0 : currField.children) || [];
|
|
@@ -3882,10 +3974,12 @@ class FormCore {
|
|
|
3882
3974
|
*/
|
|
3883
3975
|
getFormValues() {
|
|
3884
3976
|
const values = {};
|
|
3977
|
+
const metadata = {};
|
|
3885
3978
|
const erroredFields = [];
|
|
3886
3979
|
this.fields.forEach((val, key) => {
|
|
3887
3980
|
if (val.value) {
|
|
3888
3981
|
set(values, val.nameToSubmit || key, val.value);
|
|
3982
|
+
metadata[key] = val.metadata;
|
|
3889
3983
|
}
|
|
3890
3984
|
if (!val.valid) {
|
|
3891
3985
|
erroredFields.push(key);
|
|
@@ -3893,10 +3987,17 @@ class FormCore {
|
|
|
3893
3987
|
});
|
|
3894
3988
|
return {
|
|
3895
3989
|
values,
|
|
3990
|
+
metadata,
|
|
3896
3991
|
erroredFields,
|
|
3897
3992
|
isValid: this.isValid
|
|
3898
3993
|
};
|
|
3899
3994
|
}
|
|
3995
|
+
/**
|
|
3996
|
+
* function to be called to events sent from the adapter
|
|
3997
|
+
*
|
|
3998
|
+
* @param {{callback: (payload: TFieldEvent) => void}} entry.callback callback function from the adapter
|
|
3999
|
+
* @returns
|
|
4000
|
+
*/
|
|
3900
4001
|
subscribeFieldEvent({
|
|
3901
4002
|
callback
|
|
3902
4003
|
}) {
|
|
@@ -3905,6 +4006,12 @@ class FormCore {
|
|
|
3905
4006
|
});
|
|
3906
4007
|
return sub;
|
|
3907
4008
|
}
|
|
4009
|
+
/**
|
|
4010
|
+
* to be called from the adapter when the form mounts
|
|
4011
|
+
*
|
|
4012
|
+
* @param {(payload: TFormValues<T>) => void} callback
|
|
4013
|
+
* @returns Subscription
|
|
4014
|
+
*/
|
|
3908
4015
|
subscribeOnMount(callback) {
|
|
3909
4016
|
const sub = this.mountSubject$.pipe(map(() => this.getFormValues())).subscribe({
|
|
3910
4017
|
next: callback
|
|
@@ -3926,13 +4033,19 @@ class FormCore {
|
|
|
3926
4033
|
});
|
|
3927
4034
|
return sub;
|
|
3928
4035
|
}
|
|
4036
|
+
/**
|
|
4037
|
+
* method to register a callback function to be called when the form is valid
|
|
4038
|
+
*
|
|
4039
|
+
* @param {(payload: TFormValues<T>) => void} callback callback function to call when the submit action occurs
|
|
4040
|
+
*/
|
|
3929
4041
|
subscribeOnSubmit(callback) {
|
|
3930
|
-
const sub = this.submitSubject$.
|
|
4042
|
+
const sub = this.submitSubject$.subscribe({
|
|
3931
4043
|
next: callback
|
|
3932
4044
|
});
|
|
3933
4045
|
return sub;
|
|
3934
4046
|
}
|
|
3935
4047
|
/**
|
|
4048
|
+
* method to check whenever the validity status of the form changes, only emits on status change
|
|
3936
4049
|
*
|
|
3937
4050
|
* @param {(payload: TFormValidationPayload) => void} callback callback function to call onValid
|
|
3938
4051
|
*/
|
|
@@ -3947,18 +4060,6 @@ class FormCore {
|
|
|
3947
4060
|
});
|
|
3948
4061
|
return sub;
|
|
3949
4062
|
}
|
|
3950
|
-
/**
|
|
3951
|
-
* Submits the form by triggering form field events and invoking the onSubmit callback.
|
|
3952
|
-
*/
|
|
3953
|
-
mounted() {
|
|
3954
|
-
this.fields.forEach(field => {
|
|
3955
|
-
field.emitEvents({
|
|
3956
|
-
event: 'ON_FORM_MOUNT'
|
|
3957
|
-
});
|
|
3958
|
-
});
|
|
3959
|
-
const values = this.getFormValues();
|
|
3960
|
-
this.mountSubject$.next(values);
|
|
3961
|
-
}
|
|
3962
4063
|
/**
|
|
3963
4064
|
* Submits the form by triggering form field events and invoking the onSubmit callback.
|
|
3964
4065
|
*/
|
|
@@ -3972,6 +4073,9 @@ class FormCore {
|
|
|
3972
4073
|
const values = this.getFormValues();
|
|
3973
4074
|
this.submitSubject$.next(values);
|
|
3974
4075
|
}
|
|
4076
|
+
/**
|
|
4077
|
+
* recycles all the Suscriptions, to be called from the adapter when the form leaves the page
|
|
4078
|
+
*/
|
|
3975
4079
|
destroy() {
|
|
3976
4080
|
this.submitSubject$.unsubscribe();
|
|
3977
4081
|
this.templateSubscription$.unsubscribe();
|
|
@@ -4103,9 +4207,15 @@ class FormGroup {
|
|
|
4103
4207
|
formIndex,
|
|
4104
4208
|
fieldIndex
|
|
4105
4209
|
}) {
|
|
4106
|
-
var _a
|
|
4107
|
-
|
|
4108
|
-
(
|
|
4210
|
+
var _a;
|
|
4211
|
+
const form = this.forms.get(formIndex);
|
|
4212
|
+
(_a = form === null || form === void 0 ? void 0 : form.fields.get(fieldIndex)) === null || _a === void 0 ? void 0 : _a.destroyField();
|
|
4213
|
+
form === null || form === void 0 ? void 0 : form.fields.delete(fieldIndex);
|
|
4214
|
+
if ((form === null || form === void 0 ? void 0 : form.fields.size) === 0) {
|
|
4215
|
+
this.removeForm({
|
|
4216
|
+
key: formIndex
|
|
4217
|
+
});
|
|
4218
|
+
}
|
|
4109
4219
|
}
|
|
4110
4220
|
/**
|
|
4111
4221
|
* Checks if the specified key already exists in the form group.
|
|
@@ -4136,6 +4246,7 @@ class FormGroup {
|
|
|
4136
4246
|
submitMultipleFormsByIndex(indexes, callback) {
|
|
4137
4247
|
let isValid = true;
|
|
4138
4248
|
let values = {};
|
|
4249
|
+
let metadata = {};
|
|
4139
4250
|
let erroredFields = [];
|
|
4140
4251
|
indexes.forEach(index => {
|
|
4141
4252
|
var _a, _b;
|
|
@@ -4143,12 +4254,14 @@ class FormGroup {
|
|
|
4143
4254
|
const res = (_b = this.forms.get(index)) === null || _b === void 0 ? void 0 : _b.getFormValues();
|
|
4144
4255
|
isValid = isValid && ((res === null || res === void 0 ? void 0 : res.isValid) || false);
|
|
4145
4256
|
values = Object.assign(Object.assign({}, values), (res === null || res === void 0 ? void 0 : res.values) || {});
|
|
4257
|
+
metadata = Object.assign(Object.assign({}, metadata), (res === null || res === void 0 ? void 0 : res.metadata) || {});
|
|
4146
4258
|
erroredFields = [...erroredFields, ...((res === null || res === void 0 ? void 0 : res.erroredFields) || [])];
|
|
4147
4259
|
});
|
|
4148
4260
|
isValid && callback && callback({
|
|
4149
4261
|
erroredFields,
|
|
4150
4262
|
isValid,
|
|
4151
|
-
values
|
|
4263
|
+
values,
|
|
4264
|
+
metadata
|
|
4152
4265
|
});
|
|
4153
4266
|
}
|
|
4154
4267
|
onDataSubscription({
|
package/package.json
CHANGED
package/src/managers/field.d.ts
CHANGED
|
@@ -57,6 +57,10 @@ declare class FormField {
|
|
|
57
57
|
event: TEvents;
|
|
58
58
|
}>;
|
|
59
59
|
formValidNotification$: Subject<Pick<TFormValidationPayload, 'fieldTrigger'>>;
|
|
60
|
+
mountSubject$: Subject<{
|
|
61
|
+
key: string;
|
|
62
|
+
status: boolean;
|
|
63
|
+
}>;
|
|
60
64
|
validateVisibility: (payload: {
|
|
61
65
|
event: TEvents;
|
|
62
66
|
key: string;
|
|
@@ -90,7 +94,7 @@ declare class FormField {
|
|
|
90
94
|
* @param {TMapper<unknown>} options.mapper, - component generic mapper containing render parameters for adapters
|
|
91
95
|
* @param {() => TFormValues<unknown>} options.getFormValues, - form instance function that builds onData parameter payload from fields
|
|
92
96
|
*/
|
|
93
|
-
constructor({ schemaComponent, config, path, children, validateVisibility, resetValue, resetProperty, templateSubject$, fieldEventSubject$, dataSubject$, formValidNotification$, mapper, getFormValues, submitEvent, }: {
|
|
97
|
+
constructor({ schemaComponent, config, path, children, validateVisibility, resetValue, resetProperty, templateSubject$, fieldEventSubject$, dataSubject$, formValidNotification$, mountSubject$, mapper, getFormValues, submitEvent, visibility, }: {
|
|
94
98
|
schemaComponent: IComponentSchema;
|
|
95
99
|
config?: TSchemaFormConfig;
|
|
96
100
|
path?: string;
|
|
@@ -115,11 +119,18 @@ declare class FormField {
|
|
|
115
119
|
event: TEvents;
|
|
116
120
|
}>;
|
|
117
121
|
formValidNotification$: Subject<Pick<TFormValidationPayload, 'fieldTrigger'>>;
|
|
122
|
+
mountSubject$: Subject<{
|
|
123
|
+
key: string;
|
|
124
|
+
status: boolean;
|
|
125
|
+
}>;
|
|
118
126
|
mapper: TMapper<unknown>;
|
|
119
127
|
getFormValues: () => TFormValues<unknown>;
|
|
128
|
+
visibility?: boolean;
|
|
120
129
|
});
|
|
121
130
|
/**
|
|
122
131
|
* method to initialize all recycled Subjects and initialize Observers on field instance creation or rerender
|
|
132
|
+
* due to some visibility conditions unmounts the field from the adapter if they are children of it and avoid
|
|
133
|
+
* emissions to unsubscribed fields
|
|
123
134
|
*/
|
|
124
135
|
initializeObservers(): void;
|
|
125
136
|
/**
|
|
@@ -134,6 +145,13 @@ declare class FormField {
|
|
|
134
145
|
* @param {Record<string, unknown>} props - The new properties to be set.
|
|
135
146
|
*/
|
|
136
147
|
set props(props: Record<string, unknown>);
|
|
148
|
+
/**
|
|
149
|
+
* Static function to remove templates form the component props that will be shown when
|
|
150
|
+
* the field mounts and the template routine executes, to be used on the adapter
|
|
151
|
+
*
|
|
152
|
+
* @param {unknown} props - the properties from the adapter components.
|
|
153
|
+
*/
|
|
154
|
+
static filterProps(props: unknown): unknown;
|
|
137
155
|
/**
|
|
138
156
|
* Retrieves the current state value of the form field.
|
|
139
157
|
*
|
|
@@ -199,6 +217,19 @@ declare class FormField {
|
|
|
199
217
|
* @param {TApiResponse} response - The new API response data to be set.
|
|
200
218
|
*/
|
|
201
219
|
set api(response: TApiResponse);
|
|
220
|
+
/**
|
|
221
|
+
* Retrieves the mounted status of the field.
|
|
222
|
+
*
|
|
223
|
+
* @returns {boolean} - the mounted status of the field.
|
|
224
|
+
*/
|
|
225
|
+
get mounted(): boolean;
|
|
226
|
+
/**
|
|
227
|
+
* sets the mountedStatus and notifies the form that the field was mounted on the adapter
|
|
228
|
+
* and it's ready to be handled by the form instance
|
|
229
|
+
*
|
|
230
|
+
* @param {boolean} mountedStatus - the mounted status to be set from the mountField function.
|
|
231
|
+
*/
|
|
232
|
+
set mounted(mountedStatus: boolean);
|
|
202
233
|
/**
|
|
203
234
|
* Mounts the form field by initializing necessary subjects and combining their streams.
|
|
204
235
|
*
|
package/src/managers/form.d.ts
CHANGED
|
@@ -17,7 +17,10 @@ declare class FormCore {
|
|
|
17
17
|
templateSubject$: Subject<TTemplateEvent>;
|
|
18
18
|
templateSubscription$: Subscription;
|
|
19
19
|
submitSubject$: Subject<TFormValues<any>>;
|
|
20
|
-
mountSubject$: Subject<
|
|
20
|
+
mountSubject$: Subject<{
|
|
21
|
+
key: string;
|
|
22
|
+
status: boolean;
|
|
23
|
+
}>;
|
|
21
24
|
fieldEventSubject$: Subject<TFieldEvent>;
|
|
22
25
|
dataSubject$: Subject<{
|
|
23
26
|
key: string;
|
|
@@ -54,7 +57,28 @@ declare class FormCore {
|
|
|
54
57
|
* @param {((payload: {field: string;data: TFormValues;}) => void) | undefined} [entry.onData] - A callback function to handle data emission.
|
|
55
58
|
*/
|
|
56
59
|
constructor(entry: TFormEntry & Omit<IFormSchema, 'components'>);
|
|
57
|
-
|
|
60
|
+
/**
|
|
61
|
+
* mock function to simulate form mount onto the adapter
|
|
62
|
+
*/
|
|
63
|
+
generateFields(): void;
|
|
64
|
+
/**
|
|
65
|
+
* callback function passed to field instance to notify field adapter mount status
|
|
66
|
+
* once the field has all field instance properties set, this function will handle all
|
|
67
|
+
* field routines
|
|
68
|
+
*
|
|
69
|
+
* @param { string } entry.key field unique identifier
|
|
70
|
+
* @param { boolean } entry.status mount status notified from field
|
|
71
|
+
*/
|
|
72
|
+
mountActions({ key, status }: {
|
|
73
|
+
key: string;
|
|
74
|
+
status: boolean;
|
|
75
|
+
}): void;
|
|
76
|
+
/**
|
|
77
|
+
* initialValues setter to handle field values set externally from the adapter
|
|
78
|
+
*
|
|
79
|
+
* @param { Record<string, unknown> | undefined } payload initialValues to set onto fields
|
|
80
|
+
*/
|
|
81
|
+
set initialValues(payload: Record<string, unknown> | undefined);
|
|
58
82
|
/**
|
|
59
83
|
* Retrieves the internal variables (iVars) of the form.
|
|
60
84
|
*
|
|
@@ -230,6 +254,11 @@ declare class FormCore {
|
|
|
230
254
|
fieldSchema: IComponentSchema;
|
|
231
255
|
mapperElement?: TMapper<unknown>;
|
|
232
256
|
}): void;
|
|
257
|
+
/**
|
|
258
|
+
* function to be called from the adapter to remove a field when a field is removed from it
|
|
259
|
+
*
|
|
260
|
+
* @param {{ key: string }} entry.key
|
|
261
|
+
*/
|
|
233
262
|
removeField({ key }: {
|
|
234
263
|
key: string;
|
|
235
264
|
}): void;
|
|
@@ -266,9 +295,21 @@ declare class FormCore {
|
|
|
266
295
|
* @returns {TFormValues} The current form values.
|
|
267
296
|
*/
|
|
268
297
|
getFormValues<T>(): TFormValues<T>;
|
|
298
|
+
/**
|
|
299
|
+
* function to be called to events sent from the adapter
|
|
300
|
+
*
|
|
301
|
+
* @param {{callback: (payload: TFieldEvent) => void}} entry.callback callback function from the adapter
|
|
302
|
+
* @returns
|
|
303
|
+
*/
|
|
269
304
|
subscribeFieldEvent({ callback, }: {
|
|
270
305
|
callback: (payload: TFieldEvent) => void;
|
|
271
306
|
}): Subscription;
|
|
307
|
+
/**
|
|
308
|
+
* to be called from the adapter when the form mounts
|
|
309
|
+
*
|
|
310
|
+
* @param {(payload: TFormValues<T>) => void} callback
|
|
311
|
+
* @returns Subscription
|
|
312
|
+
*/
|
|
272
313
|
subscribeOnMount<T>(callback: (payload: TFormValues<T>) => void): Subscription;
|
|
273
314
|
/**
|
|
274
315
|
*
|
|
@@ -278,8 +319,14 @@ declare class FormCore {
|
|
|
278
319
|
field: string;
|
|
279
320
|
data: TFormValues<T>;
|
|
280
321
|
}) => void): Subscription;
|
|
322
|
+
/**
|
|
323
|
+
* method to register a callback function to be called when the form is valid
|
|
324
|
+
*
|
|
325
|
+
* @param {(payload: TFormValues<T>) => void} callback callback function to call when the submit action occurs
|
|
326
|
+
*/
|
|
281
327
|
subscribeOnSubmit<T>(callback: (payload: TFormValues<T>) => void): Subscription;
|
|
282
328
|
/**
|
|
329
|
+
* method to check whenever the validity status of the form changes, only emits on status change
|
|
283
330
|
*
|
|
284
331
|
* @param {(payload: TFormValidationPayload) => void} callback callback function to call onValid
|
|
285
332
|
*/
|
|
@@ -287,11 +334,10 @@ declare class FormCore {
|
|
|
287
334
|
/**
|
|
288
335
|
* Submits the form by triggering form field events and invoking the onSubmit callback.
|
|
289
336
|
*/
|
|
290
|
-
|
|
337
|
+
submit<T>(): void;
|
|
291
338
|
/**
|
|
292
|
-
*
|
|
339
|
+
* recycles all the Suscriptions, to be called from the adapter when the form leaves the page
|
|
293
340
|
*/
|
|
294
|
-
submit<T>(): void;
|
|
295
341
|
destroy(): void;
|
|
296
342
|
}
|
|
297
343
|
type TFormCore = FormCore;
|