@decaf-ts/for-angular 0.0.74 → 0.0.76

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.
@@ -12,7 +12,7 @@ import { TranslateModule, TranslatePipe, TranslateParser, provideTranslateServic
12
12
  import { Logging, LoggedClass } from '@decaf-ts/logging';
13
13
  import { Repository, OrderDirection, Condition } from '@decaf-ts/core';
14
14
  import { uses, Metadata, apply, metadata } from '@decaf-ts/decoration';
15
- import { AnimationController, provideIonicAngular, IonIcon, IonButton, IonModal, IonSpinner, IonButtons, IonContent, IonHeader, IonTitle, IonToolbar, LoadingController, IonInput, IonItem, IonCheckbox, IonRadioGroup, IonRadio, IonSelect, IonSelectOption, IonLabel, IonBadge, IonText, IonTextarea, IonCard, IonCardHeader, IonCardContent, IonCardTitle, IonCardSubtitle, IonList, IonReorder, IonReorderGroup, IonSearchbar, IonChip, IonRefresher, IonThumbnail, IonSkeletonText, IonRefresherContent, IonInfiniteScroll, IonInfiniteScrollContent, IonListHeader, IonItemSliding, IonItemOptions, IonItemOption, IonPopover, NavController } from '@ionic/angular/standalone';
15
+ import { AnimationController, provideIonicAngular, LoadingController, IonIcon, IonButton, IonModal, IonSpinner, IonButtons, IonContent, IonHeader, IonTitle, IonToolbar, IonInput, IonItem, IonCheckbox, IonRadioGroup, IonRadio, IonSelect, IonSelectOption, IonLabel, IonBadge, IonText, IonTextarea, IonCard, IonCardHeader, IonCardContent, IonCardTitle, IonCardSubtitle, IonList, IonReorder, IonReorderGroup, IonSearchbar, IonChip, IonRefresher, IonThumbnail, IonSkeletonText, IonRefresherContent, IonInfiniteScroll, IonInfiniteScrollContent, IonListHeader, IonItemSliding, IonItemOptions, IonItemOption, IonPopover, NavController } from '@ionic/angular/standalone';
16
16
  import { faker } from '@faker-js/faker';
17
17
  import { Router, NavigationStart, ActivatedRoute, NavigationEnd } from '@angular/router';
18
18
  import { forkJoin, Subject, BehaviorSubject, fromEvent, of, merge, Observable, timer, firstValueFrom, debounceTime, takeUntil as takeUntil$1, shareReplay as shareReplay$1 } from 'rxjs';
@@ -65,6 +65,10 @@ const ActionRoles = {
65
65
  submit: 'submit',
66
66
  clear: 'clear',
67
67
  back: 'back',
68
+ [OperationKeys.CREATE]: OperationKeys.CREATE,
69
+ [OperationKeys.READ]: OperationKeys.READ,
70
+ [OperationKeys.UPDATE]: OperationKeys.UPDATE,
71
+ [OperationKeys.DELETE]: OperationKeys.DELETE,
68
72
  };
69
73
  const WindowColorSchemes = {
70
74
  light: 'light',
@@ -3908,6 +3912,17 @@ class NgxComponentDirective extends DecafComponent {
3908
3912
  * @type {Location}
3909
3913
  */
3910
3914
  this.location = inject(Location);
3915
+ /**
3916
+ * @description Ionic loading overlay manager available to derived components.
3917
+ * @summary Provides convenient access to Ionic's LoadingController, enabling directive
3918
+ * subclasses to create, present, and dismiss loading overlays without wiring the
3919
+ * service themselves. Use this helper to surface async progress indicators tied to
3920
+ * CRUD operations, navigation, or any long-running UI task.
3921
+ * @type {LoadingController}
3922
+ * @returns {OverlayBaseController<LoadingOptions, HTMLIonLoadingElement>}
3923
+ * @memberOf module:lib/engine/NgxComponentDirective
3924
+ */
3925
+ this.loadingController = inject(LoadingController);
3911
3926
  /**
3912
3927
  * @description Flag indicating if the component is rendered as a child of a modal dialog.
3913
3928
  * @summary Determines whether this component instance is being displayed within a modal
@@ -4122,9 +4137,9 @@ class NgxComponentDirective extends DecafComponent {
4122
4137
  * @memberOf ListComponent
4123
4138
  */
4124
4139
  async handleRepositoryRefresh(...args) {
4125
- const [table, event, uid] = args;
4126
- if (event === OperationKeys.CREATE && !!uid)
4127
- return this.handleObserveEvent(table, event, uid);
4140
+ const [modelInstance, event, uid] = args;
4141
+ if ([OperationKeys.CREATE].includes(event))
4142
+ return this.handleObserveEvent(modelInstance, event, uid);
4128
4143
  return this.repositoryObserverSubject.next(args);
4129
4144
  }
4130
4145
  async handleObserveEvent(...args) {
@@ -5230,6 +5245,9 @@ class ModelRendererComponent extends NgxRenderableComponentDirective {
5230
5245
  if (this.output?.inputs)
5231
5246
  this.rendererId = sf(AngularEngineKeys.RENDERED_ID, this.output.inputs['rendererId']);
5232
5247
  this.instance = this.output?.component;
5248
+ const { operation } = this.globals || {};
5249
+ if (operation)
5250
+ this.operation = operation;
5233
5251
  this.subscribeEvents();
5234
5252
  }
5235
5253
  }
@@ -6091,7 +6109,6 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
6091
6109
  * @memberOf CrudFieldComponent
6092
6110
  */
6093
6111
  this.translatable = true;
6094
- this.loadingController = inject(LoadingController);
6095
6112
  addIcons({ chevronDownOutline, chevronUpOutline });
6096
6113
  }
6097
6114
  /**
@@ -6580,14 +6597,8 @@ class NgxFormDirective extends NgxParentComponentDirective {
6580
6597
  * @returns {void}
6581
6598
  */
6582
6599
  handleReset() {
6583
- if (this.isModalChild) {
6584
- this.submitEvent.emit({
6585
- data: null,
6586
- component: this.componentName,
6587
- name: ActionRoles.cancel,
6588
- });
6589
- return;
6590
- }
6600
+ if (this.isModalChild)
6601
+ return this.submitEventEmit(null, ActionRoles.cancel, this.componentName);
6591
6602
  if (![OperationKeys.DELETE, OperationKeys.READ].includes(this.operation) && this.allowClear)
6592
6603
  return NgxFormService.reset(this.formGroup);
6593
6604
  this.location.back();
@@ -6605,14 +6616,17 @@ class NgxFormDirective extends NgxParentComponentDirective {
6605
6616
  return false;
6606
6617
  }
6607
6618
  const data = NgxFormService.getFormData(this.formGroup);
6608
- if (Object.keys(data).length > 0) {
6609
- this.submitEvent.emit({
6610
- data,
6611
- component: componentName || this.componentName,
6612
- name: eventName || this.action || ComponentEventNames.SUBMIT,
6613
- handlers: this.handlers,
6614
- });
6615
- }
6619
+ if (Object.keys(data).length > 0)
6620
+ return this.submitEventEmit(data, eventName, componentName, this.handlers);
6621
+ }
6622
+ submitEventEmit(data, componentName, eventName, handlers) {
6623
+ this.submitEvent.emit({
6624
+ data,
6625
+ component: componentName || this.componentName,
6626
+ name: eventName || ComponentEventNames.SUBMIT,
6627
+ role: this.operation,
6628
+ handlers: { ...(this.handlers || {}), ...(handlers || {}) },
6629
+ });
6616
6630
  }
6617
6631
  /**
6618
6632
  * @description Updates the active form group and children for the specified page.
@@ -7110,14 +7124,10 @@ let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
7110
7124
  * @memberOf CrudFormComponent
7111
7125
  */
7112
7126
  handleDelete() {
7113
- this.submitEvent.emit({
7114
- data: this.model,
7115
- component: 'CrudFormComponent',
7116
- name: ComponentEventNames.SUBMIT,
7117
- });
7127
+ super.submitEventEmit(this.model, ComponentEventNames.SUBMIT, 'CrudFormComponent', this.handlers);
7118
7128
  }
7119
7129
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7120
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-right\">\n @if (!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ locale + '.' + (allowClear ? options.buttons.clear?.text : 'back') | translate }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : (locale + '.' + options.buttons.submit.text) | translate }}\n </ion-button>\n </div>\n\n </div>\n }\n\n </form>\n} @else {\n <section #component [id]=\"uid\">\n <ngx-decaf-layout\n [className]=\"''\"\n [children]=\"children || []\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n </section>\n\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if (operations.includes(OperationKeys.DELETE) && [OperationKeys.READ, OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{locale + '.delete' | translate}}\n </ion-button>\n </div>\n }\n @if (operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n <div>\n <ion-button\n type=\"submit\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : (locale + '.' + options.buttons.submit.text) | translate }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? (locale + '.back' | translate) : options.buttons.clear?.text}}\n </ion-button>\n </div>\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex.read,.dcf-buttons-grid.dcf-flex.delete{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex{flex-direction:column-reverse}.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "grid", "flexMode", "rowCard", "maxColsLength"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
7130
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-right\">\n @if (!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ locale + '.' + (allowClear ? options.buttons.clear?.text : 'back') | translate }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : (locale + '.' + options.buttons.submit.text) | translate }}\n </ion-button>\n </div>\n\n </div>\n }\n\n </form>\n} @else {\n <section #component [id]=\"uid\">\n <ngx-decaf-layout\n [className]=\"''\"\n [children]=\"children || []\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n </section>\n\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if ([OperationKeys.READ, OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{locale + '.delete' | translate}}\n </ion-button>\n </div>\n }\n @if (operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n <div>\n <ion-button\n type=\"submit\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : (locale + '.' + options.buttons.submit.text) | translate }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? (locale + '.back' | translate) : options.buttons.clear?.text}}\n </ion-button>\n </div>\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex.read,.dcf-buttons-grid.dcf-flex.delete{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex{flex-direction:column-reverse}.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "grid", "flexMode", "rowCard", "maxColsLength"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
7121
7131
  };
7122
7132
  CrudFormComponent = __decorate([
7123
7133
  Dynamic(),
@@ -7125,7 +7135,7 @@ CrudFormComponent = __decorate([
7125
7135
  ], CrudFormComponent);
7126
7136
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CrudFormComponent, decorators: [{
7127
7137
  type: Component,
7128
- args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [TranslatePipe, ReactiveFormsModule, LayoutComponent, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-right\">\n @if (!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ locale + '.' + (allowClear ? options.buttons.clear?.text : 'back') | translate }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : (locale + '.' + options.buttons.submit.text) | translate }}\n </ion-button>\n </div>\n\n </div>\n }\n\n </form>\n} @else {\n <section #component [id]=\"uid\">\n <ngx-decaf-layout\n [className]=\"''\"\n [children]=\"children || []\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n </section>\n\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if (operations.includes(OperationKeys.DELETE) && [OperationKeys.READ, OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{locale + '.delete' | translate}}\n </ion-button>\n </div>\n }\n @if (operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n <div>\n <ion-button\n type=\"submit\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : (locale + '.' + options.buttons.submit.text) | translate }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? (locale + '.back' | translate) : options.buttons.clear?.text}}\n </ion-button>\n </div>\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex.read,.dcf-buttons-grid.dcf-flex.delete{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex{flex-direction:column-reverse}.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"] }]
7138
+ args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [TranslatePipe, ReactiveFormsModule, LayoutComponent, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-right\">\n @if (!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ locale + '.' + (allowClear ? options.buttons.clear?.text : 'back') | translate }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : (locale + '.' + options.buttons.submit.text) | translate }}\n </ion-button>\n </div>\n\n </div>\n }\n\n </form>\n} @else {\n <section #component [id]=\"uid\">\n <ngx-decaf-layout\n [className]=\"''\"\n [children]=\"children || []\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n </section>\n\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if ([OperationKeys.READ, OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{locale + '.delete' | translate}}\n </ion-button>\n </div>\n }\n @if (operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n <div>\n <ion-button\n type=\"submit\">\n @if (options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : (locale + '.' + options.buttons.submit.text) | translate }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if (options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? (locale + '.back' | translate) : options.buttons.clear?.text}}\n </ion-button>\n </div>\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex.read,.dcf-buttons-grid.dcf-flex.delete{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex{flex-direction:column-reverse}.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"] }]
7129
7139
  }], ctorParameters: () => [] });
7130
7140
 
7131
7141
  /**
@@ -10073,7 +10083,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10073
10083
  .subscribe((event) => this.clickEventEmit(event));
10074
10084
  this.repositoryObserverSubject
10075
10085
  .pipe(debounceTime(100), shareReplay$1(1), takeUntil$1(this.destroySubscriptions$))
10076
- .subscribe(([table, event, uid]) => this.handleObserveEvent(table, event, uid));
10086
+ .subscribe(([modelInstance, event, uid]) => this.handleObserveEvent(modelInstance, event, uid));
10077
10087
  this.limit = Number(this.limit);
10078
10088
  this.start = Number(this.start);
10079
10089
  this.enableFilter = stringToBoolean(this.enableFilter);
@@ -10255,13 +10265,13 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10255
10265
  * the appropriate list operations. This includes adding new items, updating existing
10256
10266
  * ones, or removing deleted items from the list display.
10257
10267
  *
10258
- * @param {string} table - The table/model name that changed
10268
+ * @param {UIFunctionLike} clazz - The model instance that changed
10259
10269
  * @param {OperationKeys} event - The type of operation (CREATE, UPDATE, DELETE)
10260
10270
  * @param {string | number} uid - The unique identifier of the affected item
10261
10271
  * @returns {Promise<void>}
10262
10272
  * @memberOf ListComponent
10263
10273
  */
10264
- async handleObserveEvent(table, event, uid) {
10274
+ async handleObserveEvent(clazz, event, uid) {
10265
10275
  if (event === OperationKeys.CREATE) {
10266
10276
  if (uid) {
10267
10277
  await this.handleCreate(uid);
@@ -10886,7 +10896,6 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
10886
10896
  async mapResults(data) {
10887
10897
  if (!data || !data.length)
10888
10898
  return [];
10889
- // passing uid as prop to mapper
10890
10899
  this.mapper = await this.getMapper();
10891
10900
  const props = Object.assign({
10892
10901
  operations: this.operations,
@@ -11633,12 +11642,7 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxFormDirective {
11633
11642
  if (isValid) {
11634
11643
  const rootForm = this.formGroup?.root || this.formGroup;
11635
11644
  const data = Object.assign({}, ...Object.values(NgxFormService.getFormData(rootForm)));
11636
- this.submitEvent.emit({
11637
- data,
11638
- component: this.componentName,
11639
- name: this.action || ComponentEventNames.SUBMIT,
11640
- handlers: this.handlers,
11641
- });
11645
+ super.submitEventEmit(data, this.action || ComponentEventNames.SUBMIT, 'SteppedFormComponent', this.handlers);
11642
11646
  }
11643
11647
  }
11644
11648
  }
@@ -13147,21 +13151,6 @@ class NgxModelPageDirective extends NgxPageDirective {
13147
13151
  * @memberOf ModelPage
13148
13152
  */
13149
13153
  this.operation = OperationKeys.READ;
13150
- /**
13151
- * @description Array of operations allowed for the current model instance.
13152
- * @summary Dynamically determined list of operations that are permitted based on
13153
- * the current context and model state. Initially contains CREATE and READ operations,
13154
- * with UPDATE and DELETE added when a modelId is present. This controls which
13155
- * action buttons are displayed and which operations are accessible to the user.
13156
- *
13157
- * @type {OperationKeys[]}
13158
- * @default [OperationKeys.CREATE, OperationKeys.READ]
13159
- * @memberOf ModelPage
13160
- */
13161
- this.allowedOperations = [
13162
- OperationKeys.CREATE,
13163
- OperationKeys.READ,
13164
- ];
13165
13154
  /**
13166
13155
  * @description Current model data loaded from the repository.
13167
13156
  * @summary Stores the raw data object representing the current model instance retrieved
@@ -13227,7 +13216,7 @@ class NgxModelPageDirective extends NgxPageDirective {
13227
13216
  async ionViewWillEnter() {
13228
13217
  // await super.ionViewWillEnter();
13229
13218
  if (this.modelId)
13230
- this.allowedOperations = this.allowedOperations.concat([
13219
+ this.operations = this.operations.concat([
13231
13220
  OperationKeys.UPDATE,
13232
13221
  OperationKeys.DELETE,
13233
13222
  ]);