@stemy/ngx-dynamic-form 19.6.1 → 19.6.3
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/fesm2022/stemy-ngx-dynamic-form.mjs +161 -127
- package/fesm2022/stemy-ngx-dynamic-form.mjs.map +1 -1
- package/ngx-dynamic-form/common-types.d.ts +4 -0
- package/ngx-dynamic-form/utils/internal.d.ts +1 -1
- package/ngx-dynamic-form/utils/misc.d.ts +8 -1
- package/ngx-dynamic-form/utils/validation.d.ts +2 -2
- package/package.json +1 -1
- package/public_api.d.ts +1 -1
|
@@ -2,10 +2,10 @@ import * as i2 from '@stemy/ngx-utils';
|
|
|
2
2
|
import { cachedFactory, ReflectUtils, ObjectUtils, LANGUAGE_SERVICE, ForbiddenZone, API_SERVICE, StringUtils, TOASTER_SERVICE, EventsService, NgxUtilsModule } from '@stemy/ngx-utils';
|
|
3
3
|
import { of, merge, Observable, firstValueFrom, BehaviorSubject, combineLatestWith, switchMap, distinctUntilChanged, first, Subject } from 'rxjs';
|
|
4
4
|
import { debounceTime } from 'rxjs/operators';
|
|
5
|
-
import * as i0 from '@angular/core';
|
|
6
|
-
import { Inject, Injectable, untracked, input, output, inject, Renderer2, ElementRef, computed, signal, effect, HostListener, HostBinding, Directive, Type, Component, Injector, ChangeDetectionStrategy, ViewEncapsulation, makeEnvironmentProviders, NgModule } from '@angular/core';
|
|
7
5
|
import * as i1 from '@angular/forms';
|
|
8
6
|
import { FormGroup as FormGroup$1, FormArray as FormArray$1, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
7
|
+
import * as i0 from '@angular/core';
|
|
8
|
+
import { Inject, Injectable, untracked, input, output, inject, Renderer2, ElementRef, computed, signal, effect, HostListener, HostBinding, Directive, Type, Component, Injector, ChangeDetectionStrategy, ViewEncapsulation, makeEnvironmentProviders, NgModule } from '@angular/core';
|
|
9
9
|
import { outputToObservable, toSignal, rxResource } from '@angular/core/rxjs-interop';
|
|
10
10
|
import * as i3 from '@ngx-formly/core';
|
|
11
11
|
import { FieldType, ɵobserve as _observe, FieldArrayType, FieldWrapper, provideFormlyConfig, provideFormlyCore, FormlyModule } from '@ngx-formly/core';
|
|
@@ -212,10 +212,139 @@ function maxLengthValidation(maxLength, each) {
|
|
|
212
212
|
return validateEach(each, v => typeof v == "string" && v.length <= maxLength, "maxLength");
|
|
213
213
|
}
|
|
214
214
|
function minValueValidation(min, each) {
|
|
215
|
-
return validateEach(each, v =>
|
|
215
|
+
return validateEach(each, v => {
|
|
216
|
+
if (min instanceof Date) {
|
|
217
|
+
v = new Date(v);
|
|
218
|
+
return isNaN(v) || v >= min;
|
|
219
|
+
}
|
|
220
|
+
return v == null || v >= min;
|
|
221
|
+
}, "minValue");
|
|
216
222
|
}
|
|
217
223
|
function maxValueValidation(max, each) {
|
|
218
|
-
return validateEach(each, v =>
|
|
224
|
+
return validateEach(each, v => {
|
|
225
|
+
if (max instanceof Date) {
|
|
226
|
+
v = new Date(v);
|
|
227
|
+
return isNaN(v) || v <= max;
|
|
228
|
+
}
|
|
229
|
+
return v == null || v <= max;
|
|
230
|
+
}, "maxValue");
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
class ConfigForSchemaWrap {
|
|
234
|
+
opts;
|
|
235
|
+
mode;
|
|
236
|
+
injector;
|
|
237
|
+
schema;
|
|
238
|
+
get labelPrefix() {
|
|
239
|
+
return this.opts.labelPrefix;
|
|
240
|
+
}
|
|
241
|
+
get labelCustomizer() {
|
|
242
|
+
return this.opts.labelCustomizer;
|
|
243
|
+
}
|
|
244
|
+
get testId() {
|
|
245
|
+
return this.opts.testId;
|
|
246
|
+
}
|
|
247
|
+
get context() {
|
|
248
|
+
return this.opts.context;
|
|
249
|
+
}
|
|
250
|
+
fieldCustomizer;
|
|
251
|
+
constructor(opts, mode, injector, schema) {
|
|
252
|
+
this.opts = opts;
|
|
253
|
+
this.mode = mode;
|
|
254
|
+
this.injector = injector;
|
|
255
|
+
this.schema = schema;
|
|
256
|
+
this.fieldCustomizer = this.mode !== "wrap" || !ObjectUtils.isFunction(this.opts.fieldCustomizer)
|
|
257
|
+
? field => field
|
|
258
|
+
: this.opts.fieldCustomizer;
|
|
259
|
+
}
|
|
260
|
+
async customize(field, property, schema) {
|
|
261
|
+
field.defaultValue = property.format?.startsWith("date")
|
|
262
|
+
? convertToDateFormat(property.default, property.format) : property.default;
|
|
263
|
+
const res = await ForbiddenZone.run("customizer", () => this.fieldCustomizer(field, this.forCustomizer(), this.injector, property, schema));
|
|
264
|
+
return !res ? [field] : handleConfigs(res);
|
|
265
|
+
}
|
|
266
|
+
forCustomizer() {
|
|
267
|
+
return new ConfigForSchemaWrap(this.opts, "customizer", this.injector, this.schema);
|
|
268
|
+
}
|
|
269
|
+
forSchema(schema) {
|
|
270
|
+
return new ConfigForSchemaWrap(this.opts, this.mode, this.injector, schema);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
async function toWrapOptions(customizeOrOptions, injector, schema, errorMsg) {
|
|
274
|
+
if (errorMsg && ForbiddenZone.isForbidden("customizer")) {
|
|
275
|
+
throw new Error(errorMsg);
|
|
276
|
+
}
|
|
277
|
+
if (customizeOrOptions instanceof ConfigForSchemaWrap) {
|
|
278
|
+
return customizeOrOptions;
|
|
279
|
+
}
|
|
280
|
+
let schemaOptions = customizeOrOptions;
|
|
281
|
+
if (!ObjectUtils.isObject(schemaOptions)) {
|
|
282
|
+
schemaOptions = {
|
|
283
|
+
fieldCustomizer: customizeOrOptions
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
return new ConfigForSchemaWrap(schemaOptions, "wrap", injector, schema);
|
|
287
|
+
}
|
|
288
|
+
function convertToDateFormat(value, format) {
|
|
289
|
+
if (!ObjectUtils.isDefined(value))
|
|
290
|
+
return undefined;
|
|
291
|
+
value = ObjectUtils.isDate(value) ? value : new Date(value);
|
|
292
|
+
const date = isNaN(value) ? new Date() : value;
|
|
293
|
+
return format === "datetime-local" || format === "date-time"
|
|
294
|
+
? new Date(date.getTime() - date.getTimezoneOffset() * 60000)
|
|
295
|
+
.toISOString()
|
|
296
|
+
.slice(0, 16)
|
|
297
|
+
: date.toISOString().slice(0, 10);
|
|
298
|
+
}
|
|
299
|
+
function handleConfigs(configs) {
|
|
300
|
+
return Array.isArray(configs) ? configs : [configs];
|
|
301
|
+
}
|
|
302
|
+
function arrayItemActionToExpression(actionName) {
|
|
303
|
+
return (field) => {
|
|
304
|
+
const action = field.parent?.props?.[actionName];
|
|
305
|
+
// Needed to immediately reflect the changes on the view
|
|
306
|
+
field.options.detectChanges(field);
|
|
307
|
+
if (action === false)
|
|
308
|
+
return false;
|
|
309
|
+
// Returns the actual calculated value
|
|
310
|
+
return ObjectUtils.isFunction(action)
|
|
311
|
+
? action(field.formControl?.value, Number(field.key), field)
|
|
312
|
+
: true;
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function mergeFormFields(formFields) {
|
|
316
|
+
const res = [];
|
|
317
|
+
for (const formModel of formFields) {
|
|
318
|
+
for (const subModel of formModel) {
|
|
319
|
+
const index = res.findIndex(t => t.key == subModel.key);
|
|
320
|
+
if (index >= 0) {
|
|
321
|
+
res[index] = subModel;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
res.push(subModel);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return res;
|
|
328
|
+
}
|
|
329
|
+
function getFormValidationErrors(controls, parentPath = "") {
|
|
330
|
+
const errors = [];
|
|
331
|
+
Object.entries(controls).forEach(([name, control], ix) => {
|
|
332
|
+
const path = !parentPath ? name : `${parentPath}.${name}`;
|
|
333
|
+
if (control instanceof FormGroup$1) {
|
|
334
|
+
getFormValidationErrors(control.controls, path).forEach(error => errors.push(error));
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (control instanceof FormArray$1) {
|
|
338
|
+
control.controls.forEach((control, ix) => {
|
|
339
|
+
getFormValidationErrors(control.controls, `${path}.${ix}`).forEach(error => errors.push(error));
|
|
340
|
+
});
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
Object.entries(control.errors || {}).forEach(([errorKey, errorValue]) => {
|
|
344
|
+
errors.push({ control, path, errorKey, errorValue });
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
return errors;
|
|
219
348
|
}
|
|
220
349
|
|
|
221
350
|
function replaceSpecialChars(str, to = "-") {
|
|
@@ -297,11 +426,23 @@ function removeFromFieldArray(field, ix) {
|
|
|
297
426
|
model.splice(ix, 1);
|
|
298
427
|
field.options.build(field);
|
|
299
428
|
}
|
|
429
|
+
function setFieldDefault(field, value) {
|
|
430
|
+
field.defaultValue = value instanceof Date ? convertToDateFormat(value, field.props?.type || "date") : value;
|
|
431
|
+
}
|
|
432
|
+
function setFieldProps(field, values) {
|
|
433
|
+
if (!ObjectUtils.isObject(values))
|
|
434
|
+
return;
|
|
435
|
+
const props = Object.assign({}, field.props || {});
|
|
436
|
+
props.type = values.type || props.type;
|
|
437
|
+
Object.keys(values).forEach(key => {
|
|
438
|
+
const value = values[key];
|
|
439
|
+
props[key] = value instanceof Date ? convertToDateFormat(value, props.type || "date") : value;
|
|
440
|
+
});
|
|
441
|
+
field.props = props;
|
|
442
|
+
return field;
|
|
443
|
+
}
|
|
300
444
|
function setFieldProp(field, prop, value) {
|
|
301
|
-
field
|
|
302
|
-
...(field.props || {}),
|
|
303
|
-
[prop]: value
|
|
304
|
-
};
|
|
445
|
+
return setFieldProps(field, { [prop]: value });
|
|
305
446
|
}
|
|
306
447
|
function setFieldHidden(field, hidden = true) {
|
|
307
448
|
setFieldProp(field, "hidden", hidden);
|
|
@@ -328,120 +469,6 @@ const MIN_INPUT_NUM = -1999999999;
|
|
|
328
469
|
const MAX_INPUT_NUM = 1999999999;
|
|
329
470
|
const EDITOR_FORMATS = ["php", "json", "html", "css", "scss"];
|
|
330
471
|
|
|
331
|
-
class ConfigForSchemaWrap {
|
|
332
|
-
opts;
|
|
333
|
-
mode;
|
|
334
|
-
injector;
|
|
335
|
-
schema;
|
|
336
|
-
get labelPrefix() {
|
|
337
|
-
return this.opts.labelPrefix;
|
|
338
|
-
}
|
|
339
|
-
get labelCustomizer() {
|
|
340
|
-
return this.opts.labelCustomizer;
|
|
341
|
-
}
|
|
342
|
-
get testId() {
|
|
343
|
-
return this.opts.testId;
|
|
344
|
-
}
|
|
345
|
-
get context() {
|
|
346
|
-
return this.opts.context;
|
|
347
|
-
}
|
|
348
|
-
fieldCustomizer;
|
|
349
|
-
constructor(opts, mode, injector, schema) {
|
|
350
|
-
this.opts = opts;
|
|
351
|
-
this.mode = mode;
|
|
352
|
-
this.injector = injector;
|
|
353
|
-
this.schema = schema;
|
|
354
|
-
this.fieldCustomizer = this.mode !== "wrap" || !ObjectUtils.isFunction(this.opts.fieldCustomizer)
|
|
355
|
-
? field => field
|
|
356
|
-
: this.opts.fieldCustomizer;
|
|
357
|
-
}
|
|
358
|
-
async customize(field, property, schema) {
|
|
359
|
-
field.defaultValue = `${field.props?.type}`.startsWith("date")
|
|
360
|
-
? convertToDate(property.default) : property.default;
|
|
361
|
-
const res = await ForbiddenZone.run("customizer", () => this.fieldCustomizer(field, this.forCustomizer(), this.injector, property, schema));
|
|
362
|
-
return !res ? [field] : handleConfigs(res);
|
|
363
|
-
}
|
|
364
|
-
forCustomizer() {
|
|
365
|
-
return new ConfigForSchemaWrap(this.opts, "customizer", this.injector, this.schema);
|
|
366
|
-
}
|
|
367
|
-
forSchema(schema) {
|
|
368
|
-
return new ConfigForSchemaWrap(this.opts, this.mode, this.injector, schema);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
async function toWrapOptions(customizeOrOptions, injector, schema, errorMsg) {
|
|
372
|
-
if (errorMsg && ForbiddenZone.isForbidden("customizer")) {
|
|
373
|
-
throw new Error(errorMsg);
|
|
374
|
-
}
|
|
375
|
-
if (customizeOrOptions instanceof ConfigForSchemaWrap) {
|
|
376
|
-
return customizeOrOptions;
|
|
377
|
-
}
|
|
378
|
-
let schemaOptions = customizeOrOptions;
|
|
379
|
-
if (!ObjectUtils.isObject(schemaOptions)) {
|
|
380
|
-
schemaOptions = {
|
|
381
|
-
fieldCustomizer: customizeOrOptions
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
return new ConfigForSchemaWrap(schemaOptions, "wrap", injector, schema);
|
|
385
|
-
}
|
|
386
|
-
function convertToDate(value) {
|
|
387
|
-
if (ObjectUtils.isNullOrUndefined(value))
|
|
388
|
-
return null;
|
|
389
|
-
const date = ObjectUtils.isDate(value)
|
|
390
|
-
? value
|
|
391
|
-
: new Date(value);
|
|
392
|
-
return isNaN(date) ? new Date() : date;
|
|
393
|
-
}
|
|
394
|
-
function handleConfigs(configs) {
|
|
395
|
-
return Array.isArray(configs) ? configs : [configs];
|
|
396
|
-
}
|
|
397
|
-
function arrayItemActionToExpression(actionName) {
|
|
398
|
-
return (field) => {
|
|
399
|
-
const action = field.parent?.props?.[actionName];
|
|
400
|
-
// Needed to immediately reflect the changes on the view
|
|
401
|
-
field.options.detectChanges(field);
|
|
402
|
-
if (action === false)
|
|
403
|
-
return false;
|
|
404
|
-
// Returns the actual calculated value
|
|
405
|
-
return ObjectUtils.isFunction(action)
|
|
406
|
-
? action(field.formControl?.value, Number(field.key), field)
|
|
407
|
-
: true;
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
function mergeFormFields(formFields) {
|
|
411
|
-
const res = [];
|
|
412
|
-
for (const formModel of formFields) {
|
|
413
|
-
for (const subModel of formModel) {
|
|
414
|
-
const index = res.findIndex(t => t.key == subModel.key);
|
|
415
|
-
if (index >= 0) {
|
|
416
|
-
res[index] = subModel;
|
|
417
|
-
continue;
|
|
418
|
-
}
|
|
419
|
-
res.push(subModel);
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
return res;
|
|
423
|
-
}
|
|
424
|
-
function getFormValidationErrors(controls, parentPath = "") {
|
|
425
|
-
const errors = [];
|
|
426
|
-
Object.entries(controls).forEach(([name, control], ix) => {
|
|
427
|
-
const path = !parentPath ? name : `${parentPath}.${name}`;
|
|
428
|
-
if (control instanceof FormGroup$1) {
|
|
429
|
-
getFormValidationErrors(control.controls, path).forEach(error => errors.push(error));
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
if (control instanceof FormArray$1) {
|
|
433
|
-
control.controls.forEach((control, ix) => {
|
|
434
|
-
getFormValidationErrors(control.controls, `${path}.${ix}`).forEach(error => errors.push(error));
|
|
435
|
-
});
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
Object.entries(control.errors || {}).forEach(([errorKey, errorValue]) => {
|
|
439
|
-
errors.push({ control, path, errorKey, errorValue });
|
|
440
|
-
});
|
|
441
|
-
});
|
|
442
|
-
return errors;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
472
|
class DynamicFormBuilderService {
|
|
446
473
|
injector;
|
|
447
474
|
events;
|
|
@@ -546,6 +573,11 @@ class DynamicFormBuilderService {
|
|
|
546
573
|
props.min = isNaN(data.min) ? MIN_INPUT_NUM : data.min;
|
|
547
574
|
props.max = isNaN(data.max) ? MAX_INPUT_NUM : data.max;
|
|
548
575
|
break;
|
|
576
|
+
case "date":
|
|
577
|
+
case "datetime-local":
|
|
578
|
+
props.min = data.min;
|
|
579
|
+
props.max = data.max;
|
|
580
|
+
break;
|
|
549
581
|
case "string":
|
|
550
582
|
case "text":
|
|
551
583
|
case "textarea":
|
|
@@ -717,6 +749,7 @@ class DynamicFormBuilderService {
|
|
|
717
749
|
validators: {},
|
|
718
750
|
validation: {},
|
|
719
751
|
props: {
|
|
752
|
+
...(data.props || {}),
|
|
720
753
|
...props,
|
|
721
754
|
disabled: data.disabled === true,
|
|
722
755
|
hidden: data.hidden === true,
|
|
@@ -904,6 +937,7 @@ class DynamicFormSchemaService {
|
|
|
904
937
|
fieldSet: property.fieldSet,
|
|
905
938
|
componentType: property.componentType,
|
|
906
939
|
wrappers: property.wrappers,
|
|
940
|
+
props: property,
|
|
907
941
|
validators
|
|
908
942
|
};
|
|
909
943
|
}
|
|
@@ -1002,12 +1036,12 @@ class DynamicFormSchemaService {
|
|
|
1002
1036
|
// );
|
|
1003
1037
|
// }
|
|
1004
1038
|
getFormDatepickerConfig(property, options, parent) {
|
|
1039
|
+
const type = property.format == "date-time" ? "datetime-local" : "date";
|
|
1005
1040
|
return this.builder.createFormInput(property.id, {
|
|
1006
1041
|
...this.getFormFieldData(property, options),
|
|
1007
|
-
type
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
max: convertToDate(property.max),
|
|
1042
|
+
type,
|
|
1043
|
+
min: convertToDateFormat(property.min, property.format),
|
|
1044
|
+
max: convertToDateFormat(property.max, property.format),
|
|
1011
1045
|
}, parent, options);
|
|
1012
1046
|
}
|
|
1013
1047
|
getFormSelectConfig($enum, property, options, parent) {
|
|
@@ -1803,5 +1837,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
|
|
|
1803
1837
|
* Generated bundle index. Do not edit.
|
|
1804
1838
|
*/
|
|
1805
1839
|
|
|
1806
|
-
export { AsyncSubmitDirective, DynamicFieldType, DynamicFormAlertComponent, DynamicFormArrayComponent, DynamicFormBuilderService, DynamicFormChipsComponent, DynamicFormComponent, DynamicFormFieldComponent, DynamicFormFieldsetComponent, DynamicFormGroupComponent, DynamicFormSchemaService, DynamicFormService, DynamicFormUploadComponent, EDITOR_FORMATS, FORM_ROOT_ID, FormFile, FormGroup, FormInput, FormModel, FormSelect, FormSerializable, FormUpload, MAX_INPUT_NUM, MIN_INPUT_NUM, NgxDynamicFormModule, addFieldValidators, clearFieldArray, controlStatus, controlValues, customizeFormField, emailValidation, getFieldByPath, getFieldsByKey, getFieldsByPredicate, getSelectOptions, insertToFieldArray, jsonValidation, maxLengthValidation, maxValueValidation, minLengthValidation, minValueValidation, phoneValidation, removeFieldValidators, removeFromFieldArray, replaceFieldArray, replaceSpecialChars, requiredValidation, setFieldDisabled, setFieldHidden, setFieldHooks, setFieldProp, translationValidation };
|
|
1840
|
+
export { AsyncSubmitDirective, DynamicFieldType, DynamicFormAlertComponent, DynamicFormArrayComponent, DynamicFormBuilderService, DynamicFormChipsComponent, DynamicFormComponent, DynamicFormFieldComponent, DynamicFormFieldsetComponent, DynamicFormGroupComponent, DynamicFormSchemaService, DynamicFormService, DynamicFormUploadComponent, EDITOR_FORMATS, FORM_ROOT_ID, FormFile, FormGroup, FormInput, FormModel, FormSelect, FormSerializable, FormUpload, MAX_INPUT_NUM, MIN_INPUT_NUM, NgxDynamicFormModule, addFieldValidators, clearFieldArray, controlStatus, controlValues, customizeFormField, emailValidation, getFieldByPath, getFieldsByKey, getFieldsByPredicate, getSelectOptions, insertToFieldArray, jsonValidation, maxLengthValidation, maxValueValidation, minLengthValidation, minValueValidation, phoneValidation, removeFieldValidators, removeFromFieldArray, replaceFieldArray, replaceSpecialChars, requiredValidation, setFieldDefault, setFieldDisabled, setFieldHidden, setFieldHooks, setFieldProp, setFieldProps, translationValidation };
|
|
1807
1841
|
//# sourceMappingURL=stemy-ngx-dynamic-form.mjs.map
|