@smallpearl/ngx-helper 0.29.23

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.
Files changed (117) hide show
  1. package/README.md +230 -0
  2. package/core/index.d.ts +2 -0
  3. package/core/src/ngx-helper.d.ts +7 -0
  4. package/core/src/version.d.ts +1 -0
  5. package/entity-field/index.d.ts +2 -0
  6. package/entity-field/src/entity-field-spec.d.ts +69 -0
  7. package/entity-field/src/provider.d.ts +27 -0
  8. package/fesm2022/smallpearl-ngx-helper-core.mjs +23 -0
  9. package/fesm2022/smallpearl-ngx-helper-core.mjs.map +1 -0
  10. package/fesm2022/smallpearl-ngx-helper-entity-field.mjs +112 -0
  11. package/fesm2022/smallpearl-ngx-helper-entity-field.mjs.map +1 -0
  12. package/fesm2022/smallpearl-ngx-helper-forms.mjs +112 -0
  13. package/fesm2022/smallpearl-ngx-helper-forms.mjs.map +1 -0
  14. package/fesm2022/smallpearl-ngx-helper-hover-dropdown.mjs +108 -0
  15. package/fesm2022/smallpearl-ngx-helper-hover-dropdown.mjs.map +1 -0
  16. package/fesm2022/smallpearl-ngx-helper-locale.mjs +296 -0
  17. package/fesm2022/smallpearl-ngx-helper-locale.mjs.map +1 -0
  18. package/fesm2022/smallpearl-ngx-helper-mat-busy-wheel.mjs +504 -0
  19. package/fesm2022/smallpearl-ngx-helper-mat-busy-wheel.mjs.map +1 -0
  20. package/fesm2022/smallpearl-ngx-helper-mat-context-menu.mjs +184 -0
  21. package/fesm2022/smallpearl-ngx-helper-mat-context-menu.mjs.map +1 -0
  22. package/fesm2022/smallpearl-ngx-helper-mat-entity-crud.mjs +1486 -0
  23. package/fesm2022/smallpearl-ngx-helper-mat-entity-crud.mjs.map +1 -0
  24. package/fesm2022/smallpearl-ngx-helper-mat-entity-list.mjs +800 -0
  25. package/fesm2022/smallpearl-ngx-helper-mat-entity-list.mjs.map +1 -0
  26. package/fesm2022/smallpearl-ngx-helper-mat-file-input.mjs +328 -0
  27. package/fesm2022/smallpearl-ngx-helper-mat-file-input.mjs.map +1 -0
  28. package/fesm2022/smallpearl-ngx-helper-mat-form-error.mjs +468 -0
  29. package/fesm2022/smallpearl-ngx-helper-mat-form-error.mjs.map +1 -0
  30. package/fesm2022/smallpearl-ngx-helper-mat-select-entity.mjs +854 -0
  31. package/fesm2022/smallpearl-ngx-helper-mat-select-entity.mjs.map +1 -0
  32. package/fesm2022/smallpearl-ngx-helper-mat-side-menu-layout.mjs +930 -0
  33. package/fesm2022/smallpearl-ngx-helper-mat-side-menu-layout.mjs.map +1 -0
  34. package/fesm2022/smallpearl-ngx-helper-mat-tel-input.mjs +926 -0
  35. package/fesm2022/smallpearl-ngx-helper-mat-tel-input.mjs.map +1 -0
  36. package/fesm2022/smallpearl-ngx-helper-sideload.mjs +111 -0
  37. package/fesm2022/smallpearl-ngx-helper-sideload.mjs.map +1 -0
  38. package/fesm2022/smallpearl-ngx-helper-stationary-with-line-items.mjs +384 -0
  39. package/fesm2022/smallpearl-ngx-helper-stationary-with-line-items.mjs.map +1 -0
  40. package/fesm2022/smallpearl-ngx-helper.mjs +13 -0
  41. package/fesm2022/smallpearl-ngx-helper.mjs.map +1 -0
  42. package/forms/index.d.ts +1 -0
  43. package/forms/src/validation-error-handler.d.ts +52 -0
  44. package/hover-dropdown/index.d.ts +1 -0
  45. package/hover-dropdown/src/hover-dropdown.directive.d.ts +41 -0
  46. package/index.d.ts +5 -0
  47. package/locale/index.d.ts +5 -0
  48. package/locale/src/currency.pipe.d.ts +14 -0
  49. package/locale/src/date.pipe.d.ts +14 -0
  50. package/locale/src/format-currency.d.ts +1 -0
  51. package/locale/src/format-date.d.ts +2 -0
  52. package/locale/src/is-empty.d.ts +1 -0
  53. package/locale/src/providers.d.ts +20 -0
  54. package/mat-busy-wheel/index.d.ts +4 -0
  55. package/mat-busy-wheel/src/busy-wheel-op.d.ts +65 -0
  56. package/mat-busy-wheel/src/busy-wheel.component.d.ts +12 -0
  57. package/mat-busy-wheel/src/busy-wheel.service.d.ts +42 -0
  58. package/mat-busy-wheel/src/host-busy-wheel.directive.d.ts +35 -0
  59. package/mat-context-menu/index.d.ts +1 -0
  60. package/mat-context-menu/src/mat-context-menu.component.d.ts +54 -0
  61. package/mat-entity-crud/index.d.ts +5 -0
  62. package/mat-entity-crud/src/default-config.d.ts +9 -0
  63. package/mat-entity-crud/src/form-view-host.component.d.ts +34 -0
  64. package/mat-entity-crud/src/mat-entity-crud-form-base.d.ts +95 -0
  65. package/mat-entity-crud/src/mat-entity-crud-internal-types.d.ts +66 -0
  66. package/mat-entity-crud/src/mat-entity-crud-types.d.ts +141 -0
  67. package/mat-entity-crud/src/mat-entity-crud.component.d.ts +267 -0
  68. package/mat-entity-crud/src/preview-host.component.d.ts +19 -0
  69. package/mat-entity-crud/src/preview-pane.component.d.ts +27 -0
  70. package/mat-entity-crud/src/providers.d.ts +3 -0
  71. package/mat-entity-list/index.d.ts +3 -0
  72. package/mat-entity-list/src/config.d.ts +6 -0
  73. package/mat-entity-list/src/mat-entity-list-types.d.ts +53 -0
  74. package/mat-entity-list/src/mat-entity-list.component.d.ts +209 -0
  75. package/mat-entity-list/src/providers.d.ts +3 -0
  76. package/mat-file-input/README.md +63 -0
  77. package/mat-file-input/index.d.ts +1 -0
  78. package/mat-file-input/src/mat-file-input.component.d.ts +58 -0
  79. package/mat-form-error/README.md +306 -0
  80. package/mat-form-error/index.d.ts +6 -0
  81. package/mat-form-error/src/locales/en.d.ts +4 -0
  82. package/mat-form-error/src/locales/hu.d.ts +4 -0
  83. package/mat-form-error/src/locales/index.d.ts +3 -0
  84. package/mat-form-error/src/locales/pt-br.d.ts +4 -0
  85. package/mat-form-error/src/ngx-error-list.component.d.ts +9 -0
  86. package/mat-form-error/src/ngx-mat-error-control.d.ts +17 -0
  87. package/mat-form-error/src/ngx-mat-error-def.directive.d.ts +30 -0
  88. package/mat-form-error/src/ngx-mat-errors-for-date-range-picker.directive.d.ts +8 -0
  89. package/mat-form-error/src/ngx-mat-errors.component.d.ts +23 -0
  90. package/mat-form-error/src/types.d.ts +68 -0
  91. package/mat-form-error/src/utils/coerce-to-observable.d.ts +3 -0
  92. package/mat-form-error/src/utils/distinct-until-error-changed.d.ts +2 -0
  93. package/mat-form-error/src/utils/find-error-for-control.d.ts +9 -0
  94. package/mat-form-error/src/utils/get-abstract-controls.d.ts +3 -0
  95. package/mat-form-error/src/utils/get-control-with-error.d.ts +3 -0
  96. package/mat-select-entity/index.d.ts +2 -0
  97. package/mat-select-entity/src/mat-select-entity.component.d.ts +207 -0
  98. package/mat-select-entity/src/providers.d.ts +9 -0
  99. package/mat-side-menu-layout/index.d.ts +6 -0
  100. package/mat-side-menu-layout/src/layout.service.d.ts +23 -0
  101. package/mat-side-menu-layout/src/mat-menu-layout.component.d.ts +39 -0
  102. package/mat-side-menu-layout/src/mat-menu-layout.module.d.ts +18 -0
  103. package/mat-side-menu-layout/src/mat-menu-list-item.component.d.ts +36 -0
  104. package/mat-side-menu-layout/src/mat-menu-pane.component.d.ts +66 -0
  105. package/mat-side-menu-layout/src/nav-item.d.ts +10 -0
  106. package/mat-tel-input/README.md +18 -0
  107. package/mat-tel-input/index.d.ts +2 -0
  108. package/mat-tel-input/src/country-codes.d.ts +5 -0
  109. package/mat-tel-input/src/mat-telephone.component.d.ts +129 -0
  110. package/mat-tel-input/src/providers.d.ts +38 -0
  111. package/ngx-helper.d.ts +2 -0
  112. package/package.json +114 -0
  113. package/public-api.d.ts +1 -0
  114. package/sideload/index.d.ts +1 -0
  115. package/sideload/src/sideload.d.ts +17 -0
  116. package/stationary-with-line-items/index.d.ts +1 -0
  117. package/stationary-with-line-items/src/stationary-with-line-items.component.d.ts +74 -0
@@ -0,0 +1,800 @@
1
+ import * as i1 from '@angular/common/http';
2
+ import { HttpContextToken, HttpContext, HttpParams } from '@angular/common/http';
3
+ import * as i0 from '@angular/core';
4
+ import { InjectionToken, inject, input, Directive, computed, signal, viewChild, viewChildren, effect, runInInjectionContext, EventEmitter, Component, ChangeDetectionStrategy, ContentChildren, Output } from '@angular/core';
5
+ import * as i3 from '@angular/common';
6
+ import { CommonModule } from '@angular/common';
7
+ import { MatButtonModule } from '@angular/material/button';
8
+ import { MatInputModule } from '@angular/material/input';
9
+ import * as i7 from '@angular/material/paginator';
10
+ import { MatPaginatorModule } from '@angular/material/paginator';
11
+ import * as i8 from '@angular/material/progress-spinner';
12
+ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
13
+ import * as i6 from '@angular/material/sort';
14
+ import { MatSort, MatSortModule } from '@angular/material/sort';
15
+ import * as i5 from '@angular/material/table';
16
+ import { MatTableDataSource, MatTable, MatColumnDef, MatTableModule } from '@angular/material/table';
17
+ import * as i2 from '@angular/platform-browser';
18
+ import * as i4 from '@angular/router';
19
+ import { RouterModule } from '@angular/router';
20
+ import { createStore } from '@ngneat/elf';
21
+ import { withEntities, selectAllEntities, getEntitiesCount, addEntities, hasEntity, updateEntities, deleteEntities, upsertEntities } from '@ngneat/elf-entities';
22
+ import { getNgxHelperConfig } from '@smallpearl/ngx-helper/core';
23
+ import { SPEntityField, SP_ENTITY_FIELD_CONFIG } from '@smallpearl/ngx-helper/entity-field';
24
+ import { InfiniteScrollDirective } from 'ngx-infinite-scroll';
25
+ import { plural } from 'pluralize';
26
+ import { Subscription, tap, finalize } from 'rxjs';
27
+
28
+ const SP_MAT_ENTITY_LIST_HTTP_CONTEXT = new HttpContextToken(() => ({
29
+ entityName: '',
30
+ entityNamePlural: '',
31
+ endpoint: '',
32
+ }));
33
+
34
+ const SP_MAT_ENTITY_LIST_CONFIG = new InjectionToken('SPMatEntityListConfig');
35
+
36
+ const DefaultSPMatEntityListConfig = {
37
+ urlResolver: (endpoint) => endpoint,
38
+ paginator: undefined,
39
+ defaultPageSize: 50,
40
+ pageSizes: [10, 25, 50, 100],
41
+ };
42
+ /**
43
+ * To be called from an object's constructor.
44
+ */
45
+ function getEntityListConfig() {
46
+ const entityListConfig = inject(SP_MAT_ENTITY_LIST_CONFIG, {
47
+ optional: true,
48
+ });
49
+ return {
50
+ ...DefaultSPMatEntityListConfig,
51
+ ...(entityListConfig ?? {}),
52
+ };
53
+ }
54
+
55
+ class HeaderAlignmentDirective {
56
+ el;
57
+ headerAlignment = input();
58
+ constructor(el) {
59
+ this.el = el;
60
+ // this.el.nativeElement.style.backgroundColor = 'yellow';
61
+ }
62
+ ngAfterViewInit() {
63
+ if (this.headerAlignment()) {
64
+ const sortHeader = this.el.nativeElement.querySelector('.mat-sort-header-container');
65
+ if (sortHeader) {
66
+ sortHeader.style.justifyContent = this.headerAlignment();
67
+ }
68
+ else {
69
+ this.el.nativeElement.style.justifyContent = this.headerAlignment();
70
+ }
71
+ }
72
+ }
73
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: HeaderAlignmentDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
74
+ /** @nocollapse */ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.1.6", type: HeaderAlignmentDirective, isStandalone: true, selector: "[headerAlignment]", inputs: { headerAlignment: { classPropertyName: "headerAlignment", publicName: "headerAlignment", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
75
+ }
76
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: HeaderAlignmentDirective, decorators: [{
77
+ type: Directive,
78
+ args: [{
79
+ selector: '[headerAlignment]',
80
+ standalone: true
81
+ }]
82
+ }], ctorParameters: () => [{ type: i0.ElementRef }] });
83
+ /**
84
+ * A component to display a list of entities loaded from remote.
85
+ */
86
+ class SPMatEntityListComponent {
87
+ http;
88
+ sanitizer;
89
+ injector;
90
+ /* CLIENT PROVIDED PARAMETERS */
91
+ entityName = input.required();
92
+ entityNamePlural = input();
93
+ /**
94
+ * The endpoint from where the entities are to be retrieved
95
+ */
96
+ endpoint = input('');
97
+ /**
98
+ * Custom entities loader function, which if provided will be called
99
+ * instead of HttpClient.get.
100
+ */
101
+ entityLoaderFn = input(undefined);
102
+ /**
103
+ * The columns of the entity to be displayed. This is an array of
104
+ * SPEntityFieldSpec objects. If there's a one-to-one mapping between the
105
+ * column's field name, its title & the rendered value, a string can be
106
+ * specified instead. That is, the value of this property is a heterogeneous
107
+ * array consisting of SPEntityFieldSpec<> objects and strings.
108
+ */
109
+ columns = input.required();
110
+ /**
111
+ * Names of columns that are displayed. This will default to all the columns
112
+ * listed in columns.
113
+ */
114
+ displayedColumns = input([]); // ['name', 'cell', 'gender'];
115
+ /**
116
+ * Number of entities per page. If this is not set and paginator is defined,
117
+ * the number of entities int in the first request, will be taken as the
118
+ * page size.
119
+ */
120
+ pageSize = input(0);
121
+ /**
122
+ * Entity idKey, if idKey is different from the default 'id'.
123
+ */
124
+ idKey = input('id');
125
+ /**
126
+ * Type of pagination -- continuous or discrete. 'infinite' pagination
127
+ * uses an 'infiniteScroll' and 'discrete' pagination uses a mat-paginator
128
+ * at the bottom to navigate between pages.
129
+ */
130
+ pagination = input('discrete');
131
+ /**
132
+ * Component specific paginator. Only used if pagination != 'none'.
133
+ */
134
+ paginator = input();
135
+ /**
136
+ *
137
+ */
138
+ sorter = input();
139
+ /**
140
+ * Disable sorting of rows
141
+ */
142
+ disableSort = input(false);
143
+ /**
144
+ * Wrappers for infiniteScroll properties, for customization by the client
145
+ */
146
+ infiniteScrollContainer = input('');
147
+ infiniteScrollDistance = input(1);
148
+ infiniteScrollThrottle = input(400);
149
+ infiniteScrollWindow = input(false);
150
+ /**
151
+ * Custom context to be set for HttpClient requests. In the client code
152
+ * specify this property by initializing a member variable as:
153
+
154
+ ```
155
+ Component({
156
+ ...
157
+ template: `
158
+ <sp-mat-entity-list
159
+ [httpReqContext]="httpReqContext"
160
+ ></sp-mat-entity-list>
161
+ `
162
+ })
163
+ export class YourComponent {
164
+ httpReqContext: [HttpContextToken<any>, any] = [
165
+ SIDELOAD_TO_COMPOSITE_PARAMS, 'customers'
166
+ ];
167
+ }
168
+ ```
169
+ *
170
+ * Of course if you want to pass multiple context properties, declare the type
171
+ * as an array of array. That is, `[[HttpContextToken<any>, any]]` and
172
+ * initialize it appropriately.
173
+ */
174
+ httpReqContext = input();
175
+ /* END CLIENT PROVIDED PARAMETERS */
176
+ // *** INTERNAL *** //
177
+ _entityNamePlural = computed(() => this.entityNamePlural()
178
+ ? this.entityNamePlural()
179
+ : plural(this.entityName()));
180
+ _httpReqContext = computed(() => {
181
+ let reqContext = this.httpReqContext();
182
+ const context = new HttpContext();
183
+ if (reqContext && Array.isArray(reqContext)) {
184
+ if (reqContext.length == 2 && !Array.isArray(reqContext[0])) {
185
+ // one dimensional array of a key, value pair.
186
+ context.set(reqContext[0], reqContext[1]);
187
+ }
188
+ else {
189
+ reqContext.forEach(([k, v]) => context.set(k, v));
190
+ }
191
+ }
192
+ context.set(SP_MAT_ENTITY_LIST_HTTP_CONTEXT, {
193
+ entityName: this.entityName(),
194
+ entityNamePlural: this._entityNamePlural(),
195
+ endpoint: this.endpoint()
196
+ });
197
+ return context;
198
+ });
199
+ _deferViewInit = input(false);
200
+ firstLoadDone = false;
201
+ allColumnNames = signal([]);
202
+ _displayedColumns = computed(() => this.displayedColumns().length > 0
203
+ ? this.displayedColumns().filter((colName) => this.allColumnNames().find((name) => name === colName) !== undefined)
204
+ : this.allColumnNames());
205
+ dataSource = signal(new MatTableDataSource());
206
+ table = viewChild(MatTable);
207
+ sort = viewChild(MatSort);
208
+ // These are our own <ng-container matColumnDef></ng-container>
209
+ // which we create for each column that we create by the declaration:
210
+ // <ng-container *ngFor="let column of columns()" [matColumnDef]="column.name">
211
+ viewColumnDefs = viewChildren(MatColumnDef);
212
+ // These are the <ng-container matColumnDef></ng-container> placed
213
+ // inside <sp-mat-entity-list></<sp-mat-entity-list> by the client to override
214
+ // the default <ng-container matColumnDef> created by the component.
215
+ clientColumnDefs;
216
+ contentColumnDefs = [];
217
+ subs$ = new Subscription();
218
+ // Pagination state
219
+ entityCount = signal(0);
220
+ pageIndex = signal(0);
221
+ // Mechanism to default pageSize to last entities length.
222
+ lastFetchedEntitiesCount = signal(0);
223
+ _pageSize = computed(() => this.pageSize()
224
+ ? this.pageSize()
225
+ : this.entityListConfig.defaultPageSize ?? this.lastFetchedEntitiesCount());
226
+ // Effective columns, derived from columns(), which can either be an array
227
+ // of objects of array of strings.
228
+ _columns = computed(() => {
229
+ const columns = this.columns();
230
+ let fields = [];
231
+ let cols = [];
232
+ columns.forEach((colDef) => {
233
+ // fields.push(new SPEntityField(colDef))
234
+ if (typeof colDef === 'string') {
235
+ cols.push({ name: String(colDef) });
236
+ }
237
+ else if (typeof colDef === 'object') {
238
+ cols.push(colDef);
239
+ }
240
+ });
241
+ return cols;
242
+ });
243
+ __columns = computed(() => this.columns().map((colDef) => new SPEntityField(colDef, this.ngxHelperConfig, this.fieldConfig)));
244
+ // We isolate retrieving items from the remote and providing the items
245
+ // to the component into two distinct operations. The retrieval operation
246
+ // retrieves data asynchronously and then stores the data in a local store.
247
+ // The UI would be 'listening' to a reactive callback that would be triggered
248
+ // whenever items in the store changes. This is because store is an immutable
249
+ // data structure and any changes (addition/deletion) to it would result in
250
+ // the entire store being replaced with a copy with the changes applied.
251
+ // Ideally we should declare this as
252
+ // store!: Store<...>. But @ngneat/elf does not provide a generic type
253
+ // for Store<...>, which can be composed from its type arguments. Instead it
254
+ // uses type composition using its arguments to generate store's type
255
+ // implicitly. So we use the same mechanism to enforce type safety in our
256
+ // code. The code below results in a type declaration for store that is
257
+ // dependent on the components generic arguments. (Making use of TypeScript's
258
+ // type deduction system from variable assignment). Later on in the
259
+ // constructor we reassign this.store with a new object that uses the
260
+ // client provided idKey() value as the identifying key for each entity in
261
+ // the sore.
262
+ store = createStore({ name: Math.random().toString(36).slice(2) }, withEntities({ idKey: this.idKey() }));
263
+ // We'll initialize this in ngOnInit() when 'store' is initialized with the
264
+ // correct TEntity store that can be safely indexed using IdKey.
265
+ entities$;
266
+ // Effective paginator, coalescing local paginator and paginator from global
267
+ // config.
268
+ _paginator;
269
+ // We will toggle this during every entity load.
270
+ loading = signal(false);
271
+ // We will update this after every load and pagination() == 'infinite'
272
+ hasMore = signal(true);
273
+ activeEntity = signal(undefined);
274
+ activeEntityId = computed(() => this.activeEntity() ? this.activeEntity()[this.idKey()] : undefined);
275
+ _prevActiveEntity;
276
+ _activeEntityChange = effect(() => {
277
+ runInInjectionContext(this.injector, () => {
278
+ const activeEntity = this.activeEntity();
279
+ // Though we can raise the selectEntity event directly from effect handler,
280
+ // that would prevent the event handler from being able to update any
281
+ // signals from inside it. So we generate the event asyncronously.
282
+ // Also, this effect handler will be invoked for the initial 'undefined'
283
+ // during which we shouldn't emit the selectEntity event. Therefore we
284
+ // keep another state variable to filter out this state.
285
+ if (activeEntity || this._prevActiveEntity) {
286
+ setTimeout(() => {
287
+ this._prevActiveEntity = activeEntity;
288
+ this.selectEntity.emit(activeEntity);
289
+ // if (this._prevActiveEntity && !activeEntity) {
290
+ // this.selectEntity.emit(activeEntity);
291
+ // } else if (activeEntity) {
292
+ // this.selectEntity.emit(activeEntity);
293
+ // }
294
+ });
295
+ }
296
+ });
297
+ });
298
+ selectEntity = new EventEmitter();
299
+ ngxHelperConfig = getNgxHelperConfig();
300
+ fieldConfig = inject(SP_ENTITY_FIELD_CONFIG, { optional: true });
301
+ entityListConfig = getEntityListConfig();
302
+ endpointChanged = effect(() => {
303
+ runInInjectionContext(this.injector, () => {
304
+ if (this.endpoint()) {
305
+ setTimeout(() => { this.refresh(); });
306
+ }
307
+ });
308
+ });
309
+ constructor(http, sanitizer, injector) {
310
+ this.http = http;
311
+ this.sanitizer = sanitizer;
312
+ this.injector = injector;
313
+ // if (!this.config) {
314
+ // this.config = new DefaultSPMatEntityListConfig();
315
+ // }
316
+ // this.fieldConfig = inject(SP_ENTITY_FIELD_CONFIG, { optional: true })!;
317
+ }
318
+ ngOnInit() {
319
+ // This is the reactive callback that listens for changes to table entities
320
+ // which are reflected in the mat-table.
321
+ this.store = createStore({ name: Math.random().toString(36).slice(2) }, withEntities({ idKey: this.idKey() }));
322
+ this.entities$ = this.store.pipe(selectAllEntities());
323
+ this._paginator = this.paginator()
324
+ ? this.paginator()
325
+ : this.entityListConfig?.paginator;
326
+ this.subs$.add(this.entities$
327
+ .pipe(tap((entities) => {
328
+ // .data is a setter property, which ought to trigger the necessary
329
+ // signals resulting in mat-table picking up the changes without
330
+ // requiring us to call cdr.detectChanges() explicitly.
331
+ this.dataSource().data = entities;
332
+ }))
333
+ .subscribe());
334
+ }
335
+ ngOnDestroy() {
336
+ this.subs$.unsubscribe();
337
+ }
338
+ ngAfterViewInit() {
339
+ if (!this._deferViewInit()) {
340
+ this.buildContentColumnDefs();
341
+ this.buildColumns();
342
+ this.setupSort();
343
+ }
344
+ }
345
+ /**
346
+ * Clear all entities in store and reload them from endpoint as if
347
+ * the entities are being loaded for the first time.
348
+ */
349
+ refresh() {
350
+ this.pageIndex.set(0);
351
+ this.loadMoreEntities();
352
+ }
353
+ addEntity(entity) {
354
+ const pagination = this.pagination();
355
+ const count = this.store.query(getEntitiesCount());
356
+ if (pagination === 'infinite' ||
357
+ pagination === 'none' ||
358
+ count < this._pageSize()) {
359
+ this.store.update(addEntities(entity));
360
+ }
361
+ else {
362
+ // 'discrete' pagination, refresh the crud items from the beginning.
363
+ // Let component client set the behavior using a property
364
+ // this.pageIndex.set(0);
365
+ // this.loadMoreEntities();
366
+ }
367
+ }
368
+ /**
369
+ * Update an entity with a modified version. Can be used by CRUD UPDATE
370
+ * operation to update an entity in the local store that is used to as the
371
+ * source of MatTableDataSource.
372
+ * @param id
373
+ * @param entity
374
+ */
375
+ updateEntity(id, entity) {
376
+ if (this.store.query(hasEntity(id))) {
377
+ this.store.update(updateEntities(id, entity));
378
+ }
379
+ }
380
+ /**
381
+ * Clients can call this method when it has deleted and entity via a CRUD
382
+ * operation. Depending on the pagination mode, MatEntityList implements
383
+ * an appropriate behavior.
384
+ *
385
+ * If the pagination is 'infinite', the relevent entity is removed from our
386
+ * entity list. View will be repained as data store has changed.
387
+ *
388
+ * If the pagination is 'discrete', the entity is removed from the page.
389
+ * If this is the only entity in the page, the current pageNumber is
390
+ * decremented by 1 if it's possible (if the current pageNumber > 1).
391
+ * The page is reloaded from remote.
392
+ */
393
+ removeEntity(id) {
394
+ const paginator = this._paginator;
395
+ if (paginator) {
396
+ if (this.pagination() === 'infinite') {
397
+ // This will cause store to mutate which will trigger this.entity$ to
398
+ // emit which in turn will update our MatTableDataSource instance.
399
+ this.store.update(deleteEntities(id));
400
+ }
401
+ else {
402
+ // Logic
403
+ this.store.update(deleteEntities(id));
404
+ const count = this.store.query(getEntitiesCount());
405
+ if (count == 0) {
406
+ // No more entities in this page
407
+ // Go back one page
408
+ if (this.pageIndex() > 0) {
409
+ this.pageIndex.set(this.pageIndex() - 1);
410
+ }
411
+ }
412
+ // load the page again
413
+ this.loadMoreEntities();
414
+ }
415
+ }
416
+ else {
417
+ // Just remove the entity that has been deleted.
418
+ this.store.update(deleteEntities(id));
419
+ }
420
+ }
421
+ // getColumnValue(
422
+ // entity: TEntity,
423
+ // column: SPEntityFieldSpec<TEntity>
424
+ // ) {
425
+ // let val = undefined;
426
+ // if (!column.valueFn) {
427
+ // if (
428
+ // this.config?.columnValueFns &&
429
+ // this.config.columnValueFns.has(column.name)
430
+ // ) {
431
+ // val = this.config.columnValueFns.get(column.name)!(entity, column.name);
432
+ // } else {
433
+ // val = (entity as any)[column.name];
434
+ // }
435
+ // } else {
436
+ // val = column.valueFn(entity);
437
+ // }
438
+ // if (val instanceof Date) {
439
+ // return spFormatDate(val);
440
+ // } else if (typeof val === 'boolean') {
441
+ // return val ? '✔' : '✖';
442
+ // }
443
+ // return val;
444
+ // }
445
+ // getColumnLabel(column: SPEntityFieldSpec<TEntity>) {
446
+ // return this.config && this.config?.i18nTranslate
447
+ // ? this.config.i18nTranslate(column?.label || column.name)
448
+ // : column?.label || column.name;
449
+ // }
450
+ /**
451
+ * Build the contentColumnDefs array by enumerating all of client's projected
452
+ * content with matColumnDef directive.
453
+ */
454
+ buildContentColumnDefs() {
455
+ const clientColumnDefs = this.clientColumnDefs;
456
+ if (clientColumnDefs) {
457
+ this.contentColumnDefs = clientColumnDefs.toArray();
458
+ }
459
+ }
460
+ /**
461
+ * Build the effective columns by parsing our own <ng-container matColumnDef>
462
+ * statements for each column in columns() property and client's
463
+ * <ng-container matColumnDef> provided via content projection.
464
+ */
465
+ buildColumns() {
466
+ const matTable = this.table();
467
+ if (matTable) {
468
+ const columnNames = new Set();
469
+ const columnDefs = [];
470
+ this._columns().forEach((colDef) => {
471
+ if (!columnNames.has(colDef.name)) {
472
+ const matColDef = this.viewColumnDefs().find((cd) => cd.name === colDef.name);
473
+ const clientColDef = this.contentColumnDefs.find((cd) => cd.name === colDef.name);
474
+ const columnDef = clientColDef ? clientColDef : matColDef;
475
+ if (columnDef) {
476
+ columnDefs.push(columnDef);
477
+ columnNames.add(colDef.name);
478
+ }
479
+ }
480
+ });
481
+ columnDefs.forEach((cd) => {
482
+ matTable.addColumnDef(cd);
483
+ });
484
+ this.allColumnNames.set(Array.from(columnNames));
485
+ // this.displayedColumns.set(Array.from(columnNames) as string[]);
486
+ }
487
+ }
488
+ setupSort() {
489
+ const matSort = this.sort();
490
+ if (matSort) {
491
+ this.dataSource().sort = matSort;
492
+ }
493
+ }
494
+ infiniteScrollLoadNextPage(ev) {
495
+ // console.log(`infiniteScrollLoadNextPage - ${JSON.stringify(ev)}`);
496
+ if (this._paginator) {
497
+ this.loadMoreEntities();
498
+ }
499
+ }
500
+ loadMoreEntities() {
501
+ let pageParams = {};
502
+ if (this._paginator) {
503
+ pageParams = this._paginator.getRequestPageParams(this.endpoint(), this.pageIndex(), this.pageSize());
504
+ }
505
+ const parts = this.endpoint().split('?');
506
+ let params = new HttpParams(parts.length > 1 ? { fromString: parts[1] } : undefined);
507
+ for (const key in pageParams) {
508
+ params = params.append(key, pageParams[key]);
509
+ }
510
+ // Inline check for input signal value before calling its value doesn't
511
+ // seem to work as of now. So we assign the value to a const and check
512
+ // it for undefined before calling it.
513
+ const loaderFn = this.entityLoaderFn();
514
+ const obs = loaderFn !== undefined
515
+ ? loaderFn({ params })
516
+ : this.http.get(this.getUrl(parts[0]), {
517
+ context: this._httpReqContext(),
518
+ params,
519
+ });
520
+ this.loading.set(true);
521
+ this.subs$.add(obs
522
+ .pipe(tap((resp) => {
523
+ // TODO: defer this to a pagination provider so that we can support
524
+ // many types of pagination. DRF itself has different schemes. And
525
+ // express may have yet another pagination protocol.
526
+ this.firstLoadDone = true;
527
+ if (this._paginator) {
528
+ // Convert HttpParams to JS object
529
+ const paramsObj = {};
530
+ params.keys().forEach(key => {
531
+ paramsObj[key] = params.get(key);
532
+ });
533
+ const { entities, total } = this._paginator.parseRequestResponse(this.entityName(), this._entityNamePlural(), this.endpoint(), paramsObj, resp);
534
+ this.entityCount.set(total);
535
+ this.lastFetchedEntitiesCount.set(entities.length);
536
+ // this.pageIndex.set(this.pageIndex() + 1)
537
+ // entities = this._paginator.getEntitiesFromResponse(entities);
538
+ if (this.pagination() === 'discrete') {
539
+ this.store.reset();
540
+ }
541
+ else if (this.pagination() === 'infinite') {
542
+ const pageSize = this._pageSize();
543
+ const entityCount = this.entityCount();
544
+ if (pageSize > 0) {
545
+ const pageCount = Math.floor(entityCount / pageSize) +
546
+ (entityCount % pageSize ? 1 : 0);
547
+ this.hasMore.set(this.pageIndex() === pageCount);
548
+ }
549
+ else {
550
+ this.hasMore.set(false);
551
+ }
552
+ }
553
+ // store the entities in the store
554
+ // TODO: remove as any
555
+ this.store.update(upsertEntities(entities));
556
+ }
557
+ else {
558
+ this.store.update(upsertEntities(this.findArrayInResult(resp)));
559
+ }
560
+ }), finalize(() => {
561
+ this.loading.set(false);
562
+ }))
563
+ .subscribe());
564
+ }
565
+ findArrayInResult(res) {
566
+ if (Array.isArray(res)) {
567
+ return res;
568
+ }
569
+ for (const key in res) {
570
+ if (Object.prototype.hasOwnProperty.call(res, key)) {
571
+ const element = res[key];
572
+ if (Array.isArray(element)) {
573
+ return element;
574
+ }
575
+ }
576
+ }
577
+ return [];
578
+ }
579
+ handlePageEvent(e) {
580
+ this.pageIndex.set(e.pageIndex);
581
+ this.loadMoreEntities();
582
+ }
583
+ getUrl(endpoint) {
584
+ return this.entityListConfig?.urlResolver
585
+ ? this.entityListConfig?.urlResolver(endpoint)
586
+ : endpoint;
587
+ }
588
+ toggleActiveEntity(entity) {
589
+ if (entity) {
590
+ if (entity === this.activeEntity()) {
591
+ this.activeEntity.set(undefined);
592
+ }
593
+ else {
594
+ this.activeEntity.set(entity);
595
+ }
596
+ }
597
+ else {
598
+ this.activeEntity.set(undefined);
599
+ }
600
+ }
601
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: SPMatEntityListComponent, deps: [{ token: i1.HttpClient }, { token: i2.DomSanitizer }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component });
602
+ /** @nocollapse */ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.6", type: SPMatEntityListComponent, isStandalone: true, selector: "sp-mat-entity-list", inputs: { entityName: { classPropertyName: "entityName", publicName: "entityName", isSignal: true, isRequired: true, transformFunction: null }, entityNamePlural: { classPropertyName: "entityNamePlural", publicName: "entityNamePlural", isSignal: true, isRequired: false, transformFunction: null }, endpoint: { classPropertyName: "endpoint", publicName: "endpoint", isSignal: true, isRequired: false, transformFunction: null }, entityLoaderFn: { classPropertyName: "entityLoaderFn", publicName: "entityLoaderFn", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, displayedColumns: { classPropertyName: "displayedColumns", publicName: "displayedColumns", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, idKey: { classPropertyName: "idKey", publicName: "idKey", isSignal: true, isRequired: false, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: false, transformFunction: null }, paginator: { classPropertyName: "paginator", publicName: "paginator", isSignal: true, isRequired: false, transformFunction: null }, sorter: { classPropertyName: "sorter", publicName: "sorter", isSignal: true, isRequired: false, transformFunction: null }, disableSort: { classPropertyName: "disableSort", publicName: "disableSort", isSignal: true, isRequired: false, transformFunction: null }, infiniteScrollContainer: { classPropertyName: "infiniteScrollContainer", publicName: "infiniteScrollContainer", isSignal: true, isRequired: false, transformFunction: null }, infiniteScrollDistance: { classPropertyName: "infiniteScrollDistance", publicName: "infiniteScrollDistance", isSignal: true, isRequired: false, transformFunction: null }, infiniteScrollThrottle: { classPropertyName: "infiniteScrollThrottle", publicName: "infiniteScrollThrottle", isSignal: true, isRequired: false, transformFunction: null }, infiniteScrollWindow: { classPropertyName: "infiniteScrollWindow", publicName: "infiniteScrollWindow", isSignal: true, isRequired: false, transformFunction: null }, httpReqContext: { classPropertyName: "httpReqContext", publicName: "httpReqContext", isSignal: true, isRequired: false, transformFunction: null }, _deferViewInit: { classPropertyName: "_deferViewInit", publicName: "_deferViewInit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectEntity: "selectEntity" }, queries: [{ propertyName: "clientColumnDefs", predicate: MatColumnDef }], viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }, { propertyName: "viewColumnDefs", predicate: MatColumnDef, descendants: true, isSignal: true }], ngImport: i0, template: `
603
+ <div
604
+ class="entities-list-wrapper"
605
+ infiniteScroll
606
+ [infiniteScrollDistance]="infiniteScrollDistance()"
607
+ [infiniteScrollThrottle]="infiniteScrollThrottle()"
608
+ [infiniteScrollContainer]="infiniteScrollContainer()"
609
+ [scrollWindow]="infiniteScrollWindow()"
610
+ [infiniteScrollDisabled]="
611
+ pagination() !== 'infinite' || !_paginator || !hasMore()
612
+ "
613
+ (scrolled)="infiniteScrollLoadNextPage($event)"
614
+ >
615
+ <div
616
+ class="busy-overlay"
617
+ [ngClass]="{ show: pagination() === 'discrete' && loading() }"
618
+ >
619
+ <ng-container *ngTemplateOutlet="busySpinner"></ng-container>
620
+ </div>
621
+ <table mat-table [dataSource]="dataSource()">
622
+ <tr mat-header-row *matHeaderRowDef="_displayedColumns()"></tr>
623
+ <tr
624
+ mat-row
625
+ [class.active-row]="activeEntityId() === row[this.idKey()]"
626
+ *matRowDef="let row; columns: _displayedColumns()"
627
+ (click)="toggleActiveEntity(row)"
628
+ ></tr>
629
+ </table>
630
+ @if (pagination() == 'discrete' && _paginator) {
631
+ <mat-paginator
632
+ showFirstLastButtons
633
+ [length]="entityCount()"
634
+ [pageSize]="_pageSize()"
635
+ [pageIndex]="pageIndex()"
636
+ [pageSizeOptions]="[]"
637
+ [hidePageSize]="true"
638
+ (page)="handlePageEvent($event)"
639
+ [disabled]="loading()"
640
+ aria-label="Select page"
641
+ ></mat-paginator>
642
+ }
643
+ <div
644
+ class="infinite-scroll-loading"
645
+ [ngClass]="{ show: pagination() === 'infinite' && loading() }"
646
+ >
647
+ <ng-container *ngTemplateOutlet="busySpinner"></ng-container>
648
+ </div>
649
+ </div>
650
+ <!-- We keep the column definitions outside the <table> so that they can
651
+ be dynamically added to the MatTable. -->
652
+ <span matSort="sorter()">
653
+ @for (column of __columns(); track $index) {
654
+ <ng-container [matColumnDef]="column.spec.name">
655
+ @if (disableSort()) {
656
+ <th [class]="column.class" [headerAlignment]="column.options.alignment" mat-header-cell *matHeaderCellDef>
657
+ {{ column.label() }}
658
+ </th>
659
+ } @else {
660
+ <th [class]="column.class" [headerAlignment]="column.options.alignment" mat-header-cell mat-sort-header *matHeaderCellDef>
661
+ {{ column.label() }}
662
+ </th>
663
+ }
664
+ <td
665
+ [class]="column.class"
666
+ [style.text-align]="column.options.alignment"
667
+ mat-cell
668
+ *matCellDef="let element"
669
+ [routerLink]="column.getRouterLink(element)"
670
+ >
671
+ @if (column.hasRouterLink(element)) {
672
+ <a [routerLink]="column.getRouterLink(element)">
673
+ <span [innerHTML]="column.value(element)"></span>
674
+ </a>
675
+ } @else {
676
+ <span [innerHTML]="column.value(element)"></span>
677
+ }
678
+ </td>
679
+ </ng-container>
680
+ }
681
+ </span>
682
+ <ng-template #busySpinner>
683
+ <div class="busy-spinner">
684
+ <mat-spinner mode="indeterminate" diameter="28"></mat-spinner>
685
+ </div>
686
+ </ng-template>
687
+ `, isInline: true, styles: [".entities-list-wrapper{position:relative}.busy-overlay{display:none;height:100%;width:100%;position:absolute;top:0;left:0;z-index:1000;opacity:.6;background-color:transparent}.show{display:block}.busy-spinner{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.infinite-scroll-loading{display:none;width:100%;padding:8px}.active-row{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i5.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i5.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i5.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i5.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i5.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i5.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i5.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i5.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i5.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i5.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i6.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i6.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i7.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "directive", type: InfiniteScrollDirective, selector: "[infiniteScroll], [infinite-scroll], [data-infinite-scroll]", inputs: ["infiniteScrollDistance", "infiniteScrollUpDistance", "infiniteScrollThrottle", "infiniteScrollDisabled", "infiniteScrollContainer", "scrollWindow", "immediateCheck", "horizontal", "alwaysCallback", "fromRoot"], outputs: ["scrolled", "scrolledUp"] }, { kind: "directive", type: HeaderAlignmentDirective, selector: "[headerAlignment]", inputs: ["headerAlignment"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
688
+ }
689
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: SPMatEntityListComponent, decorators: [{
690
+ type: Component,
691
+ args: [{ imports: [
692
+ CommonModule,
693
+ RouterModule,
694
+ MatTableModule,
695
+ MatSortModule,
696
+ MatPaginatorModule,
697
+ MatButtonModule,
698
+ MatInputModule,
699
+ MatProgressSpinnerModule,
700
+ InfiniteScrollDirective,
701
+ HeaderAlignmentDirective,
702
+ ], selector: 'sp-mat-entity-list', template: `
703
+ <div
704
+ class="entities-list-wrapper"
705
+ infiniteScroll
706
+ [infiniteScrollDistance]="infiniteScrollDistance()"
707
+ [infiniteScrollThrottle]="infiniteScrollThrottle()"
708
+ [infiniteScrollContainer]="infiniteScrollContainer()"
709
+ [scrollWindow]="infiniteScrollWindow()"
710
+ [infiniteScrollDisabled]="
711
+ pagination() !== 'infinite' || !_paginator || !hasMore()
712
+ "
713
+ (scrolled)="infiniteScrollLoadNextPage($event)"
714
+ >
715
+ <div
716
+ class="busy-overlay"
717
+ [ngClass]="{ show: pagination() === 'discrete' && loading() }"
718
+ >
719
+ <ng-container *ngTemplateOutlet="busySpinner"></ng-container>
720
+ </div>
721
+ <table mat-table [dataSource]="dataSource()">
722
+ <tr mat-header-row *matHeaderRowDef="_displayedColumns()"></tr>
723
+ <tr
724
+ mat-row
725
+ [class.active-row]="activeEntityId() === row[this.idKey()]"
726
+ *matRowDef="let row; columns: _displayedColumns()"
727
+ (click)="toggleActiveEntity(row)"
728
+ ></tr>
729
+ </table>
730
+ @if (pagination() == 'discrete' && _paginator) {
731
+ <mat-paginator
732
+ showFirstLastButtons
733
+ [length]="entityCount()"
734
+ [pageSize]="_pageSize()"
735
+ [pageIndex]="pageIndex()"
736
+ [pageSizeOptions]="[]"
737
+ [hidePageSize]="true"
738
+ (page)="handlePageEvent($event)"
739
+ [disabled]="loading()"
740
+ aria-label="Select page"
741
+ ></mat-paginator>
742
+ }
743
+ <div
744
+ class="infinite-scroll-loading"
745
+ [ngClass]="{ show: pagination() === 'infinite' && loading() }"
746
+ >
747
+ <ng-container *ngTemplateOutlet="busySpinner"></ng-container>
748
+ </div>
749
+ </div>
750
+ <!-- We keep the column definitions outside the <table> so that they can
751
+ be dynamically added to the MatTable. -->
752
+ <span matSort="sorter()">
753
+ @for (column of __columns(); track $index) {
754
+ <ng-container [matColumnDef]="column.spec.name">
755
+ @if (disableSort()) {
756
+ <th [class]="column.class" [headerAlignment]="column.options.alignment" mat-header-cell *matHeaderCellDef>
757
+ {{ column.label() }}
758
+ </th>
759
+ } @else {
760
+ <th [class]="column.class" [headerAlignment]="column.options.alignment" mat-header-cell mat-sort-header *matHeaderCellDef>
761
+ {{ column.label() }}
762
+ </th>
763
+ }
764
+ <td
765
+ [class]="column.class"
766
+ [style.text-align]="column.options.alignment"
767
+ mat-cell
768
+ *matCellDef="let element"
769
+ [routerLink]="column.getRouterLink(element)"
770
+ >
771
+ @if (column.hasRouterLink(element)) {
772
+ <a [routerLink]="column.getRouterLink(element)">
773
+ <span [innerHTML]="column.value(element)"></span>
774
+ </a>
775
+ } @else {
776
+ <span [innerHTML]="column.value(element)"></span>
777
+ }
778
+ </td>
779
+ </ng-container>
780
+ }
781
+ </span>
782
+ <ng-template #busySpinner>
783
+ <div class="busy-spinner">
784
+ <mat-spinner mode="indeterminate" diameter="28"></mat-spinner>
785
+ </div>
786
+ </ng-template>
787
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".entities-list-wrapper{position:relative}.busy-overlay{display:none;height:100%;width:100%;position:absolute;top:0;left:0;z-index:1000;opacity:.6;background-color:transparent}.show{display:block}.busy-spinner{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.infinite-scroll-loading{display:none;width:100%;padding:8px}.active-row{font-weight:700}\n"] }]
788
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i2.DomSanitizer }, { type: i0.Injector }], propDecorators: { clientColumnDefs: [{
789
+ type: ContentChildren,
790
+ args: [MatColumnDef]
791
+ }], selectEntity: [{
792
+ type: Output
793
+ }] } });
794
+
795
+ /**
796
+ * Generated bundle index. Do not edit.
797
+ */
798
+
799
+ export { HeaderAlignmentDirective, SPMatEntityListComponent, SP_MAT_ENTITY_LIST_CONFIG, SP_MAT_ENTITY_LIST_HTTP_CONTEXT };
800
+ //# sourceMappingURL=smallpearl-ngx-helper-mat-entity-list.mjs.map