@smallpearl/ngx-helper 0.31.4 → 0.31.8

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.
@@ -4,18 +4,18 @@
4
4
  "delete": "刪除",
5
5
  "createNew": "新建",
6
6
  "refresh": "刷新",
7
- "newItem": "新建 {{item}}",
8
- "editItem": "編輯 {{item}}",
9
- "deleteItem": "刪除 {{item}}",
10
- "deleteItemConfirm": "確定要刪除這個 {{item}} 嗎?",
11
- "deleteItemSuccess": "{{item}} 刪除成功",
12
- "deleteItemError": "{{item}} 刪除失敗",
13
- "saveSuccess": "{{item}} 保存成功",
14
- "saveError": "{{item}} 保存失敗",
15
- "createSuccess": "{{item}} 創建成功",
16
- "createError": "{{item}} 創建失敗",
17
- "updateSuccess": "{{item}} 更新成功",
18
- "updateError": "{{item}} 更新失敗",
7
+ "newItem": "新建{{item}}",
8
+ "editItem": "編輯{{item}}",
9
+ "deleteItem": "刪除{{item}}",
10
+ "deleteItemConfirm": "確定要刪除這個{{item}}嗎?",
11
+ "deleteItemSuccess": "{{item}}刪除成功",
12
+ "deleteItemError": "{{item}}刪除失敗",
13
+ "saveSuccess": "{{item}}保存成功",
14
+ "saveError": "{{item}}保存失敗",
15
+ "createSuccess": "{{item}}創建成功",
16
+ "createError": "{{item}}創建失敗",
17
+ "updateSuccess": "{{item}}更新成功",
18
+ "updateError": "{{item}}更新失敗",
19
19
  "loseChangesConfirm": "您有未保存的更改。確定要離開嗎?",
20
20
  "cancel": "取消",
21
21
  "confirm": "確認",
@@ -1,2 +1,2 @@
1
- export * from './src/entity-field-spec';
1
+ export * from './src/entity-field';
2
2
  export * from './src/provider';
@@ -1,5 +1,7 @@
1
1
  import { SPIntlDateFormat } from '@smallpearl/ngx-helper/locale';
2
2
  import { SPEntityFieldConfig } from './provider';
3
+ import { Observable } from 'rxjs';
4
+ type FieldValueTypes = string | number | Date | boolean;
3
5
  /**
4
6
  * This structure defines the data formatting details for a field of the
5
7
  * entity. All entity fields need not necessarily be actual entity object's
@@ -19,7 +21,7 @@ export type SPEntityFieldSpec<TEntity extends {
19
21
  alignment?: 'start' | 'center' | 'end';
20
22
  routerLink?: ((e: TEntity) => string[]) | [string];
21
23
  };
22
- valueFn?: (item: TEntity) => string | number | Date | boolean;
24
+ valueFn?: (item: TEntity) => FieldValueTypes | Observable<FieldValueTypes>;
23
25
  };
24
26
  /**
25
27
  * A class that represents a SPEntityFieldSpec<>. This is typically used
@@ -65,3 +67,4 @@ export declare class SPEntityField<TEntity extends {
65
67
  hasRouterLink(entity: TEntity): boolean;
66
68
  getRouterLink(entity: TEntity): string[];
67
69
  }
70
+ export {};
@@ -1,5 +1,5 @@
1
1
  import { InjectionToken } from '@angular/core';
2
- import { SPEntityFieldSpec } from './entity-field-spec';
2
+ import { SPEntityFieldSpec } from './entity-field';
3
3
  export type FIELD_VALUE_FN = (entity: any, fieldName: string) => string | number | Date | boolean;
4
4
  /**
5
5
  * Global config for SPEntityField component.
@@ -1 +1 @@
1
- {"version":3,"file":"smallpearl-ngx-helper-entity-field.mjs","sources":["../../../../projects/smallpearl/ngx-helper/entity-field/src/entity-field-spec.ts","../../../../projects/smallpearl/ngx-helper/entity-field/src/provider.ts","../../../../projects/smallpearl/ngx-helper/entity-field/smallpearl-ngx-helper-entity-field.ts"],"sourcesContent":["import {\n spFormatCurrency,\n spFormatDate,\n SPIntlDateFormat,\n} from '@smallpearl/ngx-helper/locale';\nimport { SPEntityFieldConfig } from './provider';\n\n/**\n * This structure defines the data formatting details for a field of the\n * entity. All entity fields need not necessarily be actual entity object's\n * properties. Fields can also be computed fields, in which case the valueFn\n * should be initialized with a valid function to provide the field's value.\n */\nexport type SPEntityFieldSpec<TEntity extends { [P in IdKey]: PropertyKey }, IdKey extends string = 'id'> = {\n // Column name. If valueFn is not specified, this will be used as the\n // key name to retrieve the value for the column from TEntity.\n name: string;\n // If omitted, 'name' will be used as field label.\n label?: string;\n // Column value specific formatting options. Currently, only used for\n // Date types.\n valueOptions?: {\n // Specify the same format string argument that is passed to DatePipe.\n dateTimeFormat?: SPIntlDateFormat;\n // If boolean, number field will be formatted using spFormatCurrency()\n // using the current currency or 'currency' value below.\n isCurrency?: boolean;\n // Currency code, if different from default locale.\n currency?: string;\n // CSS class name; if provided will be applied to field value's wrapper\n // element. This will be <td> & <th>.\n class?: string;\n // Alignment options. Field's value will be aligned based on this.\n alignment?: 'start'|'center'|'end';\n // A fixed string or a function that returns an array of strings\n // to be used as the routerlink for the column value.\n routerLink?: ((e: TEntity) => string[])|[string];\n };\n // If the column value cannot be derived by simple TEntity[name] lookup,\n // use this function to return a custom computed or formatted value.\n valueFn?: (item: TEntity) => string | number | Date | boolean;\n};\n\n/**\n * A class that represents a SPEntityFieldSpec<>. This is typically used\n * by the library to evaluate a SPEntityFieldSpec<> object.\n */\nexport class SPEntityField<TEntity extends { [P in IdKey]: PropertyKey }, IdKey extends string = 'id'> {\n public _fieldSpec!: SPEntityFieldSpec<TEntity, IdKey>;\n\n constructor(\n spec: SPEntityFieldSpec<TEntity, IdKey> | string,\n public fieldConfig?: SPEntityFieldConfig\n ) {\n if (typeof spec === 'string') {\n this._fieldSpec = {\n name: spec,\n };\n } else {\n this._fieldSpec = spec;\n }\n }\n\n get spec() {\n return this._fieldSpec;\n }\n\n /**\n * Returns the effective fieldValueOptions by merging the global field\n * options (if one has been spefified) with the local field value options.\n * @returns SPEntityFieldSpec<any>['valueOptions']\n */\n get options() {\n let globalFieldValueOptions: SPEntityFieldSpec<any>['valueOptions'] = {};\n if (this.fieldConfig && this.fieldConfig?.fieldValueOptions && this.fieldConfig.fieldValueOptions.has(this._fieldSpec.name)) {\n globalFieldValueOptions = this.fieldConfig.fieldValueOptions.get(this._fieldSpec.name);\n }\n return {\n ...globalFieldValueOptions,\n ...(this._fieldSpec?.valueOptions ?? {})\n };\n }\n /**\n * @returns the label for the field.\n */\n label() {\n return this._fieldSpec.label ?? this._fieldSpec.name\n }\n\n /**\n * Given an entity, returns the value of the field matching the\n * SPEntityFieldSpec<> in fieldSpec.\n * @param entity TEntity instance which will be evaluated for\n * SPEntityFieldSpec<>.\n * @returns\n */\n value(entity: TEntity) {\n let val = undefined;\n if (!this._fieldSpec.valueFn) {\n if (\n this.fieldConfig &&\n this.fieldConfig?.fieldValueFns &&\n this.fieldConfig.fieldValueFns.has(this._fieldSpec.name)\n ) {\n val = this.fieldConfig.fieldValueFns.get(this._fieldSpec.name)!(entity, this._fieldSpec.name);\n } else {\n val = (entity as any)[this._fieldSpec.name];\n }\n } else {\n val = this._fieldSpec.valueFn(entity);\n }\n const valueOptions = this.options;\n if (val instanceof Date) {\n val = spFormatDate(val);\n } else if (\n typeof val === 'number' &&\n valueOptions?.isCurrency\n ) {\n val = spFormatCurrency(val, this._fieldSpec?.valueOptions?.currency);\n } else if (typeof val === 'boolean') {\n val = val ? '✔' : '✖';\n }\n return val;\n }\n\n /**\n * If specified, will be added to the CSS classes of the field's wrapper\n * element.\n */\n get class() {\n return this._fieldSpec?.valueOptions?.class ?? '';\n }\n\n hasRouterLink(entity: TEntity) {\n return !!this._fieldSpec?.valueOptions?.routerLink;\n }\n\n getRouterLink(entity: TEntity) {\n const rl = this._fieldSpec?.valueOptions?.routerLink;\n if (rl) {\n if (typeof rl == 'function') {\n return rl(entity);\n }\n return rl\n }\n return [];\n }\n}\n","import { InjectionToken } from '@angular/core';\nimport { SPEntityFieldSpec } from './entity-field-spec';\n\n\nexport type FIELD_VALUE_FN = (entity: any, fieldName: string) => string|number|Date|boolean;\n\n/**\n * Global config for SPEntityField component.\n */\nexport interface SPEntityFieldConfig {\n /**\n * These are global field value functions.\n *\n * If a value function for a field is not explicitly specified, this map is\n * looked up with the field name. If an entry exists in this table, it will\n * be used to render the field's value.\n *\n * This is useful for formatting certain fields which tend to have the\n * same name across the app. For instance fields such as 'amount', 'total'\n * or 'balance'. Or 'date', 'timestamp', etc.\n */\n fieldValueFns?: Map<string, FIELD_VALUE_FN>;\n /**\n * Similar to above, but allows setting the options for certain fields\n * globally. As in the case of `fieldValueFns`, the per field specification,\n * if one exists, takes precedence over the global setting.\n */\n fieldValueOptions?: Map<string, SPEntityFieldSpec<any>['valueOptions']>;\n}\n\nexport const SP_ENTITY_FIELD_CONFIG = new InjectionToken<SPEntityFieldConfig>(\n 'SPEntityFieldConfig'\n);\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"smallpearl-ngx-helper-entity-field.mjs","sources":["../../../../projects/smallpearl/ngx-helper/entity-field/src/entity-field.ts","../../../../projects/smallpearl/ngx-helper/entity-field/src/provider.ts","../../../../projects/smallpearl/ngx-helper/entity-field/smallpearl-ngx-helper-entity-field.ts"],"sourcesContent":["import {\n spFormatCurrency,\n spFormatDate,\n SPIntlDateFormat,\n} from '@smallpearl/ngx-helper/locale';\nimport { SPEntityFieldConfig } from './provider';\nimport { Observable } from 'rxjs';\n\ntype FieldValueTypes = string | number | Date | boolean;\n\n/**\n * This structure defines the data formatting details for a field of the\n * entity. All entity fields need not necessarily be actual entity object's\n * properties. Fields can also be computed fields, in which case the valueFn\n * should be initialized with a valid function to provide the field's value.\n */\nexport type SPEntityFieldSpec<TEntity extends { [P in IdKey]: PropertyKey }, IdKey extends string = 'id'> = {\n // Column name. If valueFn is not specified, this will be used as the\n // key name to retrieve the value for the column from TEntity.\n name: string;\n // If omitted, 'name' will be used as field label.\n label?: string;\n // Column value specific formatting options. Currently, only used for\n // Date types.\n valueOptions?: {\n // Specify the same format string argument that is passed to DatePipe.\n dateTimeFormat?: SPIntlDateFormat;\n // If boolean, number field will be formatted using spFormatCurrency()\n // using the current currency or 'currency' value below.\n isCurrency?: boolean;\n // Currency code, if different from default locale.\n currency?: string;\n // CSS class name; if provided will be applied to field value's wrapper\n // element. This will be <td> & <th>.\n class?: string;\n // Alignment options. Field's value will be aligned based on this.\n alignment?: 'start'|'center'|'end';\n // A fixed string or a function that returns an array of strings\n // to be used as the routerlink for the column value.\n routerLink?: ((e: TEntity) => string[])|[string];\n };\n // If the column value cannot be derived by simple TEntity[name] lookup,\n // use this function to return a custom computed or formatted value.\n valueFn?: (item: TEntity) => FieldValueTypes | Observable<FieldValueTypes>;\n};\n\n/**\n * A class that represents a SPEntityFieldSpec<>. This is typically used\n * by the library to evaluate a SPEntityFieldSpec<> object.\n */\nexport class SPEntityField<TEntity extends { [P in IdKey]: PropertyKey }, IdKey extends string = 'id'> {\n public _fieldSpec!: SPEntityFieldSpec<TEntity, IdKey>;\n\n constructor(\n spec: SPEntityFieldSpec<TEntity, IdKey> | string,\n public fieldConfig?: SPEntityFieldConfig\n ) {\n if (typeof spec === 'string') {\n this._fieldSpec = {\n name: spec,\n };\n } else {\n this._fieldSpec = spec;\n }\n }\n\n get spec() {\n return this._fieldSpec;\n }\n\n /**\n * Returns the effective fieldValueOptions by merging the global field\n * options (if one has been spefified) with the local field value options.\n * @returns SPEntityFieldSpec<any>['valueOptions']\n */\n get options() {\n let globalFieldValueOptions: SPEntityFieldSpec<any>['valueOptions'] = {};\n if (this.fieldConfig && this.fieldConfig?.fieldValueOptions && this.fieldConfig.fieldValueOptions.has(this._fieldSpec.name)) {\n globalFieldValueOptions = this.fieldConfig.fieldValueOptions.get(this._fieldSpec.name);\n }\n return {\n ...globalFieldValueOptions,\n ...(this._fieldSpec?.valueOptions ?? {})\n };\n }\n /**\n * @returns the label for the field.\n */\n label() {\n return this._fieldSpec.label ?? this._fieldSpec.name\n }\n\n /**\n * Given an entity, returns the value of the field matching the\n * SPEntityFieldSpec<> in fieldSpec.\n * @param entity TEntity instance which will be evaluated for\n * SPEntityFieldSpec<>.\n * @returns\n */\n value(entity: TEntity) {\n let val = undefined;\n if (!this._fieldSpec.valueFn) {\n if (\n this.fieldConfig &&\n this.fieldConfig?.fieldValueFns &&\n this.fieldConfig.fieldValueFns.has(this._fieldSpec.name)\n ) {\n val = this.fieldConfig.fieldValueFns.get(this._fieldSpec.name)!(entity, this._fieldSpec.name);\n } else {\n val = (entity as any)[this._fieldSpec.name];\n }\n } else {\n val = this._fieldSpec.valueFn(entity);\n }\n const valueOptions = this.options;\n if (val instanceof Date) {\n val = spFormatDate(val);\n } else if (\n typeof val === 'number' &&\n valueOptions?.isCurrency\n ) {\n val = spFormatCurrency(val, this._fieldSpec?.valueOptions?.currency);\n } else if (typeof val === 'boolean') {\n val = val ? '✔' : '✖';\n }\n return val;\n }\n\n /**\n * If specified, will be added to the CSS classes of the field's wrapper\n * element.\n */\n get class() {\n return this._fieldSpec?.valueOptions?.class ?? '';\n }\n\n hasRouterLink(entity: TEntity) {\n return !!this._fieldSpec?.valueOptions?.routerLink;\n }\n\n getRouterLink(entity: TEntity) {\n const rl = this._fieldSpec?.valueOptions?.routerLink;\n if (rl) {\n if (typeof rl == 'function') {\n return rl(entity);\n }\n return rl\n }\n return [];\n }\n}\n","import { InjectionToken } from '@angular/core';\nimport { SPEntityFieldSpec } from './entity-field';\n\n\nexport type FIELD_VALUE_FN = (entity: any, fieldName: string) => string|number|Date|boolean;\n\n/**\n * Global config for SPEntityField component.\n */\nexport interface SPEntityFieldConfig {\n /**\n * These are global field value functions.\n *\n * If a value function for a field is not explicitly specified, this map is\n * looked up with the field name. If an entry exists in this table, it will\n * be used to render the field's value.\n *\n * This is useful for formatting certain fields which tend to have the\n * same name across the app. For instance fields such as 'amount', 'total'\n * or 'balance'. Or 'date', 'timestamp', etc.\n */\n fieldValueFns?: Map<string, FIELD_VALUE_FN>;\n /**\n * Similar to above, but allows setting the options for certain fields\n * globally. As in the case of `fieldValueFns`, the per field specification,\n * if one exists, takes precedence over the global setting.\n */\n fieldValueOptions?: Map<string, SPEntityFieldSpec<any>['valueOptions']>;\n}\n\nexport const SP_ENTITY_FIELD_CONFIG = new InjectionToken<SPEntityFieldConfig>(\n 'SPEntityFieldConfig'\n);\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import * as i1$1 from '@angular/common/http';
2
2
  import { HttpContextToken, HttpContext } from '@angular/common/http';
3
3
  import * as i0 from '@angular/core';
4
- import { InjectionToken, inject, input, signal, viewChild, ViewContainerRef, Component, ChangeDetectionStrategy, computed, viewChildren, EventEmitter, effect, ContentChildren, Output, ChangeDetectorRef } from '@angular/core';
4
+ import { InjectionToken, inject, input, computed, signal, viewChild, ViewContainerRef, Component, ChangeDetectionStrategy, viewChildren, EventEmitter, effect, ContentChildren, Output, ChangeDetectorRef } from '@angular/core';
5
5
  import * as i4 from '@angular/common';
6
6
  import { CommonModule } from '@angular/common';
7
7
  import * as i1 from '@angular/material/button';
@@ -27,7 +27,7 @@ import * as i11 from 'angular-split';
27
27
  import { AngularSplitModule } from 'angular-split';
28
28
  import { startCase } from 'lodash';
29
29
  import { plural } from 'pluralize';
30
- import { Subscription, tap, Observable, of, switchMap, map } from 'rxjs';
30
+ import { Observable, of, Subscription, firstValueFrom, tap, switchMap, map } from 'rxjs';
31
31
  import * as i1$2 from '@angular/material/toolbar';
32
32
  import { MatToolbarModule } from '@angular/material/toolbar';
33
33
  import { setServerErrorsAsFormErrors } from '@smallpearl/ngx-helper/forms';
@@ -82,6 +82,14 @@ class FormViewHostComponent {
82
82
  clientViewTemplate = input(null);
83
83
  itemLabel = input.required();
84
84
  itemLabelPlural = input.required();
85
+ _itemLabel = computed(() => {
86
+ const label = this.itemLabel();
87
+ return label instanceof Observable ? label : of(label);
88
+ });
89
+ _itemLabelPlural = computed(() => {
90
+ const label = this.itemLabelPlural();
91
+ return label instanceof Observable ? label : of(label);
92
+ });
85
93
  entity = signal(undefined);
86
94
  title = signal('');
87
95
  params = signal(undefined);
@@ -103,10 +111,17 @@ class FormViewHostComponent {
103
111
  this.title.set(params.title);
104
112
  }
105
113
  else {
114
+ firstValueFrom(this._itemLabel()).then((itemLabel) => {
115
+ this.title.set(this.transloco.translate(entity ? 'editItem' : 'newItem', {
116
+ item: itemLabel,
117
+ }));
118
+ });
106
119
  // this.title.set(entity ? this.config.i18n.editItemLabel(this.itemLabel()) : this.config.i18n.newItemLabel(this.itemLabel()));
107
- this.title.set(this.transloco.translate(entity ? 'editItem' : 'newItem', {
108
- item: this.itemLabel(),
109
- }));
120
+ // this.title.set(
121
+ // this.transloco.translate(entity ? 'editItem' : 'newItem', {
122
+ // item: this.itemLabel(),
123
+ // })
124
+ // );
110
125
  }
111
126
  this.params.set(params);
112
127
  this.createClientView();
@@ -126,7 +141,9 @@ class FormViewHostComponent {
126
141
  // )}`
127
142
  // );
128
143
  const crudComponent = this.entityCrudComponentBase();
129
- return crudComponent?.create(entityValue).pipe(tap(() => this.close(false)));
144
+ return crudComponent
145
+ ?.create(entityValue)
146
+ .pipe(tap(() => this.close(false)));
130
147
  }
131
148
  update(id, entityValue) {
132
149
  // console.log(
@@ -135,7 +152,9 @@ class FormViewHostComponent {
135
152
  // )}, entity: ${entityValue}`
136
153
  // );
137
154
  const crudComponent = this.entityCrudComponentBase();
138
- return crudComponent?.update(id, entityValue).pipe(tap(() => this.close(false)));
155
+ return crudComponent
156
+ ?.update(id, entityValue)
157
+ .pipe(tap(() => this.close(false)));
139
158
  }
140
159
  /**
141
160
  * Creates the client view provided via template
@@ -149,7 +168,7 @@ class FormViewHostComponent {
149
168
  $implicit: {
150
169
  bridge: this,
151
170
  entity: this.entity(),
152
- params: this.params()
171
+ params: this.params(),
153
172
  },
154
173
  });
155
174
  this.clientFormView.detectChanges();
@@ -189,7 +208,12 @@ class FormViewHostComponent {
189
208
  }
190
209
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: FormViewHostComponent, decorators: [{
191
210
  type: Component,
192
- args: [{ imports: [CommonModule, MatButtonModule, MatIconModule, SPMatHostBusyWheelDirective], selector: 'sp-create-edit-entity-host', template: `
211
+ args: [{ imports: [
212
+ CommonModule,
213
+ MatButtonModule,
214
+ MatIconModule,
215
+ SPMatHostBusyWheelDirective,
216
+ ], selector: 'sp-create-edit-entity-host', template: `
193
217
  <div spHostBusyWheel="formBusyWheel">
194
218
  <div class="create-edit-topbar">
195
219
  <div class="title">
@@ -440,12 +464,18 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
440
464
  }
441
465
  return startCase(source);
442
466
  };
443
- _itemLabel = computed(() => this.itemLabel()
444
- ? this.itemLabel()
445
- : this.getLabel(this.entityName()));
446
- _itemLabelPlural = computed(() => this.itemLabelPlural()
447
- ? this.itemLabelPlural()
448
- : this.getLabel(plural(this.entityName())));
467
+ _itemLabel = computed(() => {
468
+ const itemLabel = this.itemLabel();
469
+ const label = itemLabel ? itemLabel : this.getLabel(this.entityName());
470
+ return label instanceof Observable ? label : of(label);
471
+ });
472
+ _itemLabelPlural = computed(() => {
473
+ const itemLabelPlural = this.itemLabelPlural();
474
+ const label = itemLabelPlural
475
+ ? itemLabelPlural
476
+ : this.getLabel(plural(this.entityName()));
477
+ return label instanceof Observable ? label : of(label);
478
+ });
449
479
  // Computed title
450
480
  _title = computed(() => {
451
481
  const title = this.title() ? this.title() : this._itemLabelPlural();
@@ -570,16 +600,14 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
570
600
  ]);
571
601
  }
572
602
  }
573
- ngOnInit() {
574
- }
603
+ ngOnInit() { }
575
604
  ngOnDestroy() {
576
605
  this.sub$.unsubscribe();
577
606
  }
578
607
  /**
579
608
  * Override so that we can suppress default action in SPMatEntityListComponent
580
609
  */
581
- ngAfterViewInit() {
582
- }
610
+ ngAfterViewInit() { }
583
611
  /**
584
612
  * If the create/edit entity form is active, it calls its registered
585
613
  * canCancelEdit callback to determine if it's okay to cancel the edit.
@@ -742,36 +770,49 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
742
770
  if (!this.newItemLink() || this.newItemLink()?.length == 0) {
743
771
  event.preventDefault();
744
772
  event.stopImmediatePropagation();
745
- const params = {
746
- title: this.newItemLabel() ??
747
- this.transloco.translate('spMatEntityCrud.newItem', {
748
- item: this._itemLabel(),
749
- }),
750
- };
751
- this.showCreateEditView(undefined, params);
752
- // const tmpl = this.createEditFormTemplate();
753
- // if (tmpl) {
754
- // // If preview is active deactivate it
755
- // if (this.previewActive()) {
756
- // this.closePreview();
757
- // }
758
- // const createEditHost = this.createEditHostComponent();
759
- // createEditHost!.show(undefined);
760
- // this.createEditViewActive.set(true);
761
- // }
762
- }
763
- if (!this.createEditViewActive()) {
764
- this.action.emit({ role: '_new_' });
773
+ firstValueFrom(this._itemLabel()).then((itemLabel) => {
774
+ const params = {
775
+ title: this.newItemLabel() ??
776
+ this.transloco.translate('spMatEntityCrud.newItem', {
777
+ item: itemLabel
778
+ }),
779
+ };
780
+ this.showCreateEditView(undefined, params);
781
+ if (!this.createEditViewActive()) {
782
+ this.action.emit({ role: '_new_' });
783
+ }
784
+ });
785
+ // const params = {
786
+ // title:
787
+ // this.newItemLabel() ??
788
+ // this.transloco.translate('spMatEntityCrud.newItem', {
789
+ // item: this._itemLabel(),
790
+ // }),
791
+ // };
792
+ // this.showCreateEditView(undefined, params);
765
793
  }
766
794
  }
767
795
  onUpdate(entity) {
768
- const params = {
769
- title: this.editItemTitle() ??
770
- this.transloco.translate('spMatEntityCrud.editItem', {
771
- item: this._itemLabel(),
772
- }),
773
- };
774
- this.showCreateEditView(entity, params);
796
+ firstValueFrom(this._itemLabel()).then((itemLabel) => {
797
+ const params = {
798
+ title: this.editItemTitle() ??
799
+ this.transloco.translate('spMatEntityCrud.editItem', {
800
+ item: itemLabel
801
+ }),
802
+ };
803
+ this.showCreateEditView(entity, params);
804
+ if (!this.createEditViewActive()) {
805
+ this.action.emit({ role: '_update_' });
806
+ }
807
+ });
808
+ // const params = {
809
+ // title:
810
+ // this.editItemTitle() ??
811
+ // this.transloco.translate('spMatEntityCrud.editItem', {
812
+ // item: this._itemLabel(),
813
+ // }),
814
+ // };
815
+ // this.showCreateEditView(entity, params);
775
816
  // const tmpl = this.createEditFormTemplate();
776
817
  // if (tmpl) {
777
818
  // // If preview is active deactivate it
@@ -784,9 +825,9 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
784
825
  // this.createEditViewActive.set(true);
785
826
  // }
786
827
  // }
787
- if (!this.createEditViewActive()) {
788
- this.action.emit({ role: '_update_' });
789
- }
828
+ // if (!this.createEditViewActive()) {
829
+ // this.action.emit({ role: '_update_' });
830
+ // }
790
831
  }
791
832
  /**
792
833
  * Show the create/edit component. This is deliberately made public so as to
@@ -840,36 +881,41 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
840
881
  // Do the delete prompt asynchronously so that the context menu is
841
882
  // dismissed before the prompt is displayed.
842
883
  setTimeout(() => {
843
- const deletedItemPrompt = this.transloco.translate('spMatEntityCrud.deleteItemConfirm', { item: this._itemLabel().toLocaleLowerCase() });
844
- const yes = confirm(deletedItemPrompt);
845
- if (yes) {
846
- const entityId = entity[this.idKey()];
847
- // If preview is active deactivate it
848
- if (this.previewActive()) {
849
- this.closePreviewImpl(false);
850
- }
851
- let obs;
852
- const crudOpFn = this.crudOpFn();
853
- if (crudOpFn) {
854
- obs = crudOpFn('delete', entityId, undefined, this);
884
+ // We use firstValueFrom() to get the value of the observable
885
+ // synchronously. firstValueFrom() also gracefully cleans up the
886
+ // observable after a value is emitted.
887
+ firstValueFrom(this._itemLabel()).then((itemLabel) => {
888
+ const deletedItemPrompt = this.transloco.translate('spMatEntityCrud.deleteItemConfirm', { item: itemLabel.toLocaleLowerCase() });
889
+ const yes = confirm(deletedItemPrompt);
890
+ if (yes) {
891
+ const entityId = entity[this.idKey()];
892
+ // If preview is active deactivate it
893
+ if (this.previewActive()) {
894
+ this.closePreviewImpl(false);
895
+ }
896
+ let obs;
897
+ const crudOpFn = this.crudOpFn();
898
+ if (crudOpFn) {
899
+ obs = crudOpFn('delete', entityId, undefined, this);
900
+ }
901
+ else {
902
+ obs = this.http.delete(this.getEntityUrl(entityId), {
903
+ context: this.getCrudReqHttpContext('delete'),
904
+ });
905
+ }
906
+ this.sub$.add(obs
907
+ .pipe(
908
+ // TODO: how to display a busy wheel?
909
+ // showBusyWheelUntilComplete(this.busyWheelId),
910
+ tap(() => {
911
+ this.spEntitiesList().removeEntity(entityId);
912
+ // TODO: customize by providing an interface via SPMatEntityCrudConfig?
913
+ const deletedMessage = this.transloco.translate('spMatEntityCrud.deleteItemSuccess', { item: this._itemLabel() });
914
+ this.snackBar.open(deletedMessage);
915
+ }))
916
+ .subscribe());
855
917
  }
856
- else {
857
- obs = this.http.delete(this.getEntityUrl(entityId), {
858
- context: this.getCrudReqHttpContext('delete'),
859
- });
860
- }
861
- this.sub$.add(obs
862
- .pipe(
863
- // TODO: how to display a busy wheel?
864
- // showBusyWheelUntilComplete(this.busyWheelId),
865
- tap(() => {
866
- this.spEntitiesList().removeEntity(entityId);
867
- // TODO: customize by providing an interface via SPMatEntityCrudConfig?
868
- const deletedMessage = this.transloco.translate('spMatEntityCrud.deleteItemSuccess', { item: this._itemLabel() });
869
- this.snackBar.open(deletedMessage);
870
- }))
871
- .subscribe());
872
- }
918
+ });
873
919
  });
874
920
  }
875
921
  getUrl(endpoint) {
@@ -1048,7 +1094,9 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
1048
1094
  >
1049
1095
  {{
1050
1096
  newItemLabel() ??
1051
- t('spMatEntityCrud.createNew', { item: _itemLabel() })
1097
+ t('spMatEntityCrud.newItem', {
1098
+ item: _itemLabel() | async
1099
+ })
1052
1100
  }}
1053
1101
  <mat-icon>expand_circle_down</mat-icon>
1054
1102
  </button>
@@ -1073,7 +1121,9 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
1073
1121
  >
1074
1122
  {{
1075
1123
  newItemLabel() ??
1076
- t('spMatEntityCrud.createNew', { item: _itemLabel() })
1124
+ t('spMatEntityCrud.newItem', {
1125
+ item: _itemLabel() | async
1126
+ })
1077
1127
  }}
1078
1128
  <mat-icon>add_circle</mat-icon>
1079
1129
  </button>
@@ -1127,10 +1177,7 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
1127
1177
  -->
1128
1178
  <ng-container matColumnDef="action">
1129
1179
  <th mat-header-cell *matHeaderCellDef></th>
1130
- <td
1131
- mat-cell
1132
- *matCellDef="let element"
1133
- >
1180
+ <td mat-cell *matCellDef="let element">
1134
1181
  <!-- <button
1135
1182
  mat-icon-button
1136
1183
  hoverDropDown
@@ -1159,8 +1206,8 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
1159
1206
  <!-- Create/Edit Entity -->
1160
1207
  <sp-create-edit-entity-host
1161
1208
  [ngClass]="createEditViewActive() ? 'd-inherit' : 'd-none'"
1162
- [itemLabel]="_itemLabel()"
1163
- [itemLabelPlural]="_itemLabelPlural()"
1209
+ itemLabel="{{ _itemLabel() | async }}"
1210
+ itemLabelPlural="{{ _itemLabelPlural() | async }}"
1164
1211
  [entityCrudComponentBase]="this"
1165
1212
  [clientViewTemplate]="createEditFormTemplate()"
1166
1213
  ></sp-create-edit-entity-host>
@@ -1208,7 +1255,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
1208
1255
  >
1209
1256
  {{
1210
1257
  newItemLabel() ??
1211
- t('spMatEntityCrud.createNew', { item: _itemLabel() })
1258
+ t('spMatEntityCrud.newItem', {
1259
+ item: _itemLabel() | async
1260
+ })
1212
1261
  }}
1213
1262
  <mat-icon>expand_circle_down</mat-icon>
1214
1263
  </button>
@@ -1233,7 +1282,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
1233
1282
  >
1234
1283
  {{
1235
1284
  newItemLabel() ??
1236
- t('spMatEntityCrud.createNew', { item: _itemLabel() })
1285
+ t('spMatEntityCrud.newItem', {
1286
+ item: _itemLabel() | async
1287
+ })
1237
1288
  }}
1238
1289
  <mat-icon>add_circle</mat-icon>
1239
1290
  </button>
@@ -1287,10 +1338,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
1287
1338
  -->
1288
1339
  <ng-container matColumnDef="action">
1289
1340
  <th mat-header-cell *matHeaderCellDef></th>
1290
- <td
1291
- mat-cell
1292
- *matCellDef="let element"
1293
- >
1341
+ <td mat-cell *matCellDef="let element">
1294
1342
  <!-- <button
1295
1343
  mat-icon-button
1296
1344
  hoverDropDown
@@ -1319,8 +1367,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
1319
1367
  <!-- Create/Edit Entity -->
1320
1368
  <sp-create-edit-entity-host
1321
1369
  [ngClass]="createEditViewActive() ? 'd-inherit' : 'd-none'"
1322
- [itemLabel]="_itemLabel()"
1323
- [itemLabelPlural]="_itemLabelPlural()"
1370
+ itemLabel="{{ _itemLabel() | async }}"
1371
+ itemLabelPlural="{{ _itemLabelPlural() | async }}"
1324
1372
  [entityCrudComponentBase]="this"
1325
1373
  [clientViewTemplate]="createEditFormTemplate()"
1326
1374
  ></sp-create-edit-entity-host>