@stemy/ngx-dynamic-form 19.9.12 → 19.9.13

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.
@@ -1337,13 +1337,23 @@ class DynamicFormSchemaService {
1337
1337
  }, parent, options);
1338
1338
  }
1339
1339
  getFormSelectOptions($enum, property, options, field) {
1340
- if (Array.isArray($enum)) {
1341
- return this.getFormEnumOptions($enum, property.id, options, field);
1340
+ // --- Handle options from another property path ---
1341
+ if (ObjectUtils.isStringWithValue(property.optionsPath)) {
1342
+ return this.getFormPathOptions(property.optionsPath, field);
1342
1343
  }
1344
+ // --- Handle options from an endpoint ---
1343
1345
  if (ObjectUtils.isStringWithValue(property.endpoint)) {
1344
1346
  return this.getFormEndpointOptions(property, field);
1345
1347
  }
1346
- return this.getFormPathOptions(property.optionsPath, field);
1348
+ // --- Handle direct options like an enum ---
1349
+ if (Array.isArray(property.options)) {
1350
+ return this.getFormEnumOptions(property.options, property.id, options, field);
1351
+ }
1352
+ // --- Handle enum options ---
1353
+ if (Array.isArray($enum)) {
1354
+ return this.getFormEnumOptions($enum, property.id, options, field);
1355
+ }
1356
+ return [];
1347
1357
  }
1348
1358
  getFormEnumOptions($enum, id, options, field) {
1349
1359
  return this.builder.language.pipe(distinctUntilChanged(), switchMap(async () => {
@@ -1497,20 +1507,30 @@ class DynamicFormService {
1497
1507
  return this.getFormFieldGroupBySchemaName(name, customizeOrOptions, "getFormFieldsForSchema");
1498
1508
  }
1499
1509
  async getFormFieldGroupBySchemaName(name, customizeOrOptions, restrictedMethod) {
1500
- const config = {
1501
- id: FORM_ROOT_ID,
1502
- path: "",
1503
- wrappers: ["form-group"],
1504
- props: {}
1505
- };
1506
1510
  const schema = await this.fs.getSchema(name);
1507
1511
  if (!schema) {
1508
1512
  console.warn(`Schema with name "${name}" not found.`);
1509
- return config;
1513
+ return {
1514
+ id: FORM_ROOT_ID,
1515
+ path: "",
1516
+ wrappers: ["form-group"],
1517
+ fieldGroup: [],
1518
+ props: {},
1519
+ hooks: {},
1520
+ expressions: {}
1521
+ };
1510
1522
  }
1511
1523
  const wrapOptions = await toWrapOptions(customizeOrOptions, this.injector, schema, `"DynamicFormService.${restrictedMethod}" is called from a customizer, which is not allowed. Please use DynamicFormSchemaService instead!`);
1512
- const fields = await this.fs.getFormFieldsForSchema(schema, config, wrapOptions);
1524
+ const config = await this.fb.createFormGroup(null, parent => {
1525
+ return this.fs.getFormFieldsForSchema(schema, parent, wrapOptions);
1526
+ }, {
1527
+ label: "",
1528
+ hidden: false,
1529
+ className: "dynamic-form-root-group"
1530
+ }, null, wrapOptions);
1531
+ const fields = config.fieldGroup || [];
1513
1532
  const fieldGroup = [...fields];
1533
+ config.id = FORM_ROOT_ID;
1514
1534
  config.fieldGroup = fieldGroup;
1515
1535
  // There are no actual fields in the schema, or no schema exists
1516
1536
  if (fields.length === 0)
@@ -2023,16 +2043,16 @@ class DynamicFormComponent {
2023
2043
  legacyLabels: this.legacyLabels(),
2024
2044
  testId: this.testId(),
2025
2045
  };
2026
- const fields = this.fields();
2046
+ const defs = this.fields();
2047
+ const fields = Array.isArray(defs) ? defs : null;
2027
2048
  const constructor = this.data()?.constructor;
2028
- return [
2029
- this.builder.createFormGroup(null, parent => this.builder.createFieldSets(fields || this.builder.resolveFormFields(constructor, parent, options), parent), {
2030
- label: "",
2031
- useTabs: this.useTabs(),
2032
- hidden: false,
2033
- className: "dynamic-form-root-group"
2034
- })
2035
- ];
2049
+ const root = (Array.isArray(defs) ? null : defs) ?? this.builder.createFormGroup(null, parent => this.builder.createFieldSets(fields ?? this.builder.resolveFormFields(constructor, parent, options), parent), {
2050
+ label: "",
2051
+ hidden: false,
2052
+ useTabs: this.useTabs(),
2053
+ className: "dynamic-form-root-group"
2054
+ });
2055
+ return [root];
2036
2056
  });
2037
2057
  group = computed(() => {
2038
2058
  this.config();
@@ -2254,11 +2274,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.19", ngImpo
2254
2274
 
2255
2275
  class DynamicFormGroupComponent extends FieldWrapper {
2256
2276
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.19", ngImport: i0, type: DynamicFormGroupComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2257
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.19", type: DynamicFormGroupComponent, isStandalone: false, selector: "dynamic-form-group", usesInheritance: true, ngImport: i0, template: "<ng-template #innerLabelTemplate let-label=\"label\">\n <label class=\"field-label\" [for]=\"id\">\n <span [innerHTML]=\"label | safe: 'html'\"></span>\n @if (props.markRequired) {\n <span class=\"field-required\" aria-hidden=\"true\">*</span>\n }\n @if (props.description) {\n <p class=\"field-description\" [innerHTML]=\"props.description | translate | safe: 'html'\"></p>\n }\n </label>\n</ng-template>\n<ng-template #labelTemplate>\n @let label = !props.label || props.hideLabel ? null : props.label | translate;\n @if (label) {\n <ng-container [ngxTemplateOutlet]=\"(field | dynamicFormTemplate : 'label') || innerLabelTemplate\"\n [context]=\"field\"\n [additionalContext]=\"{label: label}\"></ng-container>\n }\n</ng-template>\n@if (field.display) {\n @if (props.labelAlign === \"before\") {\n <ng-container [ngTemplateOutlet]=\"labelTemplate\"></ng-container>\n }\n <tabs class=\"field-container\">\n @for (itemField of field.fieldGroup; track itemField; let ix = $index) {\n @if (itemField.display) {\n @if (props.useTabs && itemField.wrappers | includes: 'form-fieldset') {\n <div class=\"form-fieldset-item\"\n [tabsItem]=\"ix\"\n [classes]=\"['form-fieldset-tab', itemField.valid === false ? 'invalid' : 'valid']\"\n [label]=\"itemField.props.label\">\n <formly-field [field]=\"itemField\"></formly-field>\n </div>\n } @else {\n <formly-field [field]=\"itemField\"></formly-field>\n }\n }\n }\n @if (showError && field.key !== null) {\n <div *ngIf=\"showError\" class=\"field-errors invalid-feedback\">\n <formly-validation-message\n [field]=\"field\"\n id=\"{{ id }}-formly-validation-error\"\n role=\"alert\"\n ></formly-validation-message>\n </div>\n }\n </tabs>\n @if (props.labelAlign === \"after\") {\n <ng-container [ngTemplateOutlet]=\"labelTemplate\"></ng-container>\n }\n}\n", styles: [".form-fieldset-item.hidden-tab{display:none}.form-fieldset-tab{position:relative;--invalid-bg: rgba(184, 38, 38, 1);--invalid-border: rgba(184, 38, 38, .6);--invalid-color: #ececec;--invalid-box-size: 15px;--invalid-box-pull: -3px}.form-fieldset-tab.invalid>btn .async-target{border:1px solid var(--invalid-border)}.form-fieldset-tab.invalid:after{background:var(--invalid-bg);color:var(--invalid-color);font-size:10px;line-height:var(--invalid-box-size);width:var(--invalid-box-size);height:var(--invalid-box-size);text-align:center;border-radius:5px;content:\"!\";display:block;position:absolute;top:var(--invalid-box-pull);right:var(--invalid-box-pull)}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.NgxTemplateOutletDirective, selector: "[ngxTemplateOutlet]", inputs: ["context", "additionalContext", "ngxTemplateOutlet"] }, { kind: "directive", type: i2.TabsItemDirective, selector: "[tabsItem]", inputs: ["tabsItem", "label", "tooltip", "icon", "disabled", "classes"] }, { kind: "component", type: i2.TabsComponent, selector: "tabs", inputs: ["value", "options", "type", "size", "testId", "tabsClass"], outputs: ["valueChange", "selectedChange"] }, { kind: "component", type: i3.LegacyFormlyField, selector: "formly-field" }, { kind: "component", type: i3.LegacyFormlyValidationMessage, selector: "formly-validation-message" }, { kind: "pipe", type: i2.IncludesPipe, name: "includes" }, { kind: "pipe", type: i2.SafeHtmlPipe, name: "safe" }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "pipe", type: DynamicFormTemplatePipe, name: "dynamicFormTemplate" }], encapsulation: i0.ViewEncapsulation.None });
2277
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.19", type: DynamicFormGroupComponent, isStandalone: false, selector: "dynamic-form-group", usesInheritance: true, ngImport: i0, template: "<ng-template #innerLabelTemplate let-label=\"label\">\n <label class=\"field-label\" [for]=\"id\">\n <span [innerHTML]=\"label | safe: 'html'\"></span>\n @if (props.markRequired) {\n <span class=\"field-required\" aria-hidden=\"true\">*</span>\n }\n @if (props.description) {\n <p class=\"field-description\" [innerHTML]=\"props.description | translate | safe: 'html'\"></p>\n }\n </label>\n</ng-template>\n<ng-template #labelTemplate>\n @let label = !props.label || props.hideLabel ? null : props.label | translate;\n @if (label) {\n <ng-container [ngxTemplateOutlet]=\"(field | dynamicFormTemplate : 'label') || innerLabelTemplate\"\n [context]=\"field\"\n [additionalContext]=\"{label: label}\"></ng-container>\n }\n</ng-template>\n@if (field.display) {\n @if (props.labelAlign === \"before\") {\n <ng-container [ngTemplateOutlet]=\"labelTemplate\"></ng-container>\n }\n <tabs class=\"field-container\" [testId]=\"(field.testId || 'form') + '-tab'\">\n @for (itemField of field.fieldGroup; track itemField) {\n @if (itemField.display) {\n @if (props.useTabs && itemField.wrappers | includes: 'form-fieldset') {\n <div class=\"form-fieldset-item\"\n [tabsItem]=\"itemField.id\"\n [classes]=\"['form-fieldset-tab', itemField.valid === false ? 'invalid' : 'valid']\"\n [label]=\"itemField.props.label\">\n <formly-field [field]=\"itemField\"></formly-field>\n </div>\n } @else {\n <formly-field [field]=\"itemField\"></formly-field>\n }\n }\n }\n @if (showError && field.key !== null) {\n <div *ngIf=\"showError\" class=\"field-errors invalid-feedback\">\n <formly-validation-message\n [field]=\"field\"\n id=\"{{ id }}-formly-validation-error\"\n role=\"alert\"\n ></formly-validation-message>\n </div>\n }\n </tabs>\n @if (props.labelAlign === \"after\") {\n <ng-container [ngTemplateOutlet]=\"labelTemplate\"></ng-container>\n }\n}\n", styles: [".form-fieldset-item.hidden-tab{display:none}.form-fieldset-tab{position:relative;--invalid-bg: rgba(184, 38, 38, 1);--invalid-border: rgba(184, 38, 38, .6);--invalid-color: #ececec;--invalid-box-size: 15px;--invalid-box-pull: -3px}.form-fieldset-tab.invalid>btn .async-target{border:1px solid var(--invalid-border)}.form-fieldset-tab.invalid:after{background:var(--invalid-bg);color:var(--invalid-color);font-size:10px;line-height:var(--invalid-box-size);width:var(--invalid-box-size);height:var(--invalid-box-size);text-align:center;border-radius:5px;content:\"!\";display:block;position:absolute;top:var(--invalid-box-pull);right:var(--invalid-box-pull)}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.NgxTemplateOutletDirective, selector: "[ngxTemplateOutlet]", inputs: ["context", "additionalContext", "ngxTemplateOutlet"] }, { kind: "directive", type: i2.TabsItemDirective, selector: "[tabsItem]", inputs: ["tabsItem", "label", "tooltip", "icon", "disabled", "classes"] }, { kind: "component", type: i2.TabsComponent, selector: "tabs", inputs: ["value", "options", "type", "size", "testId", "tabsClass"], outputs: ["valueChange", "selectedChange"] }, { kind: "component", type: i3.LegacyFormlyField, selector: "formly-field" }, { kind: "component", type: i3.LegacyFormlyValidationMessage, selector: "formly-validation-message" }, { kind: "pipe", type: i2.IncludesPipe, name: "includes" }, { kind: "pipe", type: i2.SafeHtmlPipe, name: "safe" }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "pipe", type: DynamicFormTemplatePipe, name: "dynamicFormTemplate" }], encapsulation: i0.ViewEncapsulation.None });
2258
2278
  }
2259
2279
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.19", ngImport: i0, type: DynamicFormGroupComponent, decorators: [{
2260
2280
  type: Component,
2261
- args: [{ standalone: false, selector: "dynamic-form-group", encapsulation: ViewEncapsulation.None, template: "<ng-template #innerLabelTemplate let-label=\"label\">\n <label class=\"field-label\" [for]=\"id\">\n <span [innerHTML]=\"label | safe: 'html'\"></span>\n @if (props.markRequired) {\n <span class=\"field-required\" aria-hidden=\"true\">*</span>\n }\n @if (props.description) {\n <p class=\"field-description\" [innerHTML]=\"props.description | translate | safe: 'html'\"></p>\n }\n </label>\n</ng-template>\n<ng-template #labelTemplate>\n @let label = !props.label || props.hideLabel ? null : props.label | translate;\n @if (label) {\n <ng-container [ngxTemplateOutlet]=\"(field | dynamicFormTemplate : 'label') || innerLabelTemplate\"\n [context]=\"field\"\n [additionalContext]=\"{label: label}\"></ng-container>\n }\n</ng-template>\n@if (field.display) {\n @if (props.labelAlign === \"before\") {\n <ng-container [ngTemplateOutlet]=\"labelTemplate\"></ng-container>\n }\n <tabs class=\"field-container\">\n @for (itemField of field.fieldGroup; track itemField; let ix = $index) {\n @if (itemField.display) {\n @if (props.useTabs && itemField.wrappers | includes: 'form-fieldset') {\n <div class=\"form-fieldset-item\"\n [tabsItem]=\"ix\"\n [classes]=\"['form-fieldset-tab', itemField.valid === false ? 'invalid' : 'valid']\"\n [label]=\"itemField.props.label\">\n <formly-field [field]=\"itemField\"></formly-field>\n </div>\n } @else {\n <formly-field [field]=\"itemField\"></formly-field>\n }\n }\n }\n @if (showError && field.key !== null) {\n <div *ngIf=\"showError\" class=\"field-errors invalid-feedback\">\n <formly-validation-message\n [field]=\"field\"\n id=\"{{ id }}-formly-validation-error\"\n role=\"alert\"\n ></formly-validation-message>\n </div>\n }\n </tabs>\n @if (props.labelAlign === \"after\") {\n <ng-container [ngTemplateOutlet]=\"labelTemplate\"></ng-container>\n }\n}\n", styles: [".form-fieldset-item.hidden-tab{display:none}.form-fieldset-tab{position:relative;--invalid-bg: rgba(184, 38, 38, 1);--invalid-border: rgba(184, 38, 38, .6);--invalid-color: #ececec;--invalid-box-size: 15px;--invalid-box-pull: -3px}.form-fieldset-tab.invalid>btn .async-target{border:1px solid var(--invalid-border)}.form-fieldset-tab.invalid:after{background:var(--invalid-bg);color:var(--invalid-color);font-size:10px;line-height:var(--invalid-box-size);width:var(--invalid-box-size);height:var(--invalid-box-size);text-align:center;border-radius:5px;content:\"!\";display:block;position:absolute;top:var(--invalid-box-pull);right:var(--invalid-box-pull)}\n"] }]
2281
+ args: [{ standalone: false, selector: "dynamic-form-group", encapsulation: ViewEncapsulation.None, template: "<ng-template #innerLabelTemplate let-label=\"label\">\n <label class=\"field-label\" [for]=\"id\">\n <span [innerHTML]=\"label | safe: 'html'\"></span>\n @if (props.markRequired) {\n <span class=\"field-required\" aria-hidden=\"true\">*</span>\n }\n @if (props.description) {\n <p class=\"field-description\" [innerHTML]=\"props.description | translate | safe: 'html'\"></p>\n }\n </label>\n</ng-template>\n<ng-template #labelTemplate>\n @let label = !props.label || props.hideLabel ? null : props.label | translate;\n @if (label) {\n <ng-container [ngxTemplateOutlet]=\"(field | dynamicFormTemplate : 'label') || innerLabelTemplate\"\n [context]=\"field\"\n [additionalContext]=\"{label: label}\"></ng-container>\n }\n</ng-template>\n@if (field.display) {\n @if (props.labelAlign === \"before\") {\n <ng-container [ngTemplateOutlet]=\"labelTemplate\"></ng-container>\n }\n <tabs class=\"field-container\" [testId]=\"(field.testId || 'form') + '-tab'\">\n @for (itemField of field.fieldGroup; track itemField) {\n @if (itemField.display) {\n @if (props.useTabs && itemField.wrappers | includes: 'form-fieldset') {\n <div class=\"form-fieldset-item\"\n [tabsItem]=\"itemField.id\"\n [classes]=\"['form-fieldset-tab', itemField.valid === false ? 'invalid' : 'valid']\"\n [label]=\"itemField.props.label\">\n <formly-field [field]=\"itemField\"></formly-field>\n </div>\n } @else {\n <formly-field [field]=\"itemField\"></formly-field>\n }\n }\n }\n @if (showError && field.key !== null) {\n <div *ngIf=\"showError\" class=\"field-errors invalid-feedback\">\n <formly-validation-message\n [field]=\"field\"\n id=\"{{ id }}-formly-validation-error\"\n role=\"alert\"\n ></formly-validation-message>\n </div>\n }\n </tabs>\n @if (props.labelAlign === \"after\") {\n <ng-container [ngTemplateOutlet]=\"labelTemplate\"></ng-container>\n }\n}\n", styles: [".form-fieldset-item.hidden-tab{display:none}.form-fieldset-tab{position:relative;--invalid-bg: rgba(184, 38, 38, 1);--invalid-border: rgba(184, 38, 38, .6);--invalid-color: #ececec;--invalid-box-size: 15px;--invalid-box-pull: -3px}.form-fieldset-tab.invalid>btn .async-target{border:1px solid var(--invalid-border)}.form-fieldset-tab.invalid:after{background:var(--invalid-bg);color:var(--invalid-color);font-size:10px;line-height:var(--invalid-box-size);width:var(--invalid-box-size);height:var(--invalid-box-size);text-align:center;border-radius:5px;content:\"!\";display:block;position:absolute;top:var(--invalid-box-pull);right:var(--invalid-box-pull)}\n"] }]
2262
2282
  }] });
2263
2283
 
2264
2284
  // --- Components ---