@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.
@@ -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 => typeof v == "number" && v >= min, "minValue");
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 => typeof v == "number" && v <= max, "maxValue");
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.props = {
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: property.format == "date-time" ? "datetime-local" : "date",
1008
- // format: property.dateFormat || "dd.MM.yyyy",
1009
- min: convertToDate(property.min),
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