@rosoftlab/ionic 1.0.0-alpha-0

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 (48) hide show
  1. package/README.md +27 -0
  2. package/esm2022/lib/components/index.mjs +4 -0
  3. package/esm2022/lib/components/rsl-ionic-crud.component/rsl-ionic-crud.component.mjs +266 -0
  4. package/esm2022/lib/components/rsl-ionic-data-table/rsl-ionic-data-table.component.mjs +292 -0
  5. package/esm2022/lib/components/rsl-ionic-grid/rsl-ionic-grid.component.mjs +269 -0
  6. package/esm2022/lib/decorators/index.mjs +3 -0
  7. package/esm2022/lib/decorators/ionic-datatable-layout.mjs +10 -0
  8. package/esm2022/lib/decorators/ionic-list.decorator.mjs +9 -0
  9. package/esm2022/lib/interfaces/index.mjs +2 -0
  10. package/esm2022/lib/interfaces/ionic-list-layout-config.mjs +2 -0
  11. package/esm2022/lib/ionic-dialog.service.mjs +51 -0
  12. package/esm2022/lib/rsl-ionic-module.module.mjs +86 -0
  13. package/esm2022/lib/translate.extension.mjs +48 -0
  14. package/esm2022/lib/types/index.mjs +2 -0
  15. package/esm2022/lib/types/repeat/repeat-section.type.mjs +135 -0
  16. package/esm2022/lib/validators/index.mjs +2 -0
  17. package/esm2022/lib/validators/must-match.mjs +12 -0
  18. package/esm2022/lib/wrappers/accordion-wrapper.component.mjs +50 -0
  19. package/esm2022/lib/wrappers/index.mjs +3 -0
  20. package/esm2022/lib/wrappers/panel-wrapper.component.mjs +37 -0
  21. package/esm2022/lib/wrappers/wrappers.module.mjs +56 -0
  22. package/esm2022/public-api.mjs +12 -0
  23. package/esm2022/rosoftlab-ionic.mjs +5 -0
  24. package/fesm2022/rosoftlab-ionic.mjs +1251 -0
  25. package/fesm2022/rosoftlab-ionic.mjs.map +1 -0
  26. package/index.d.ts +5 -0
  27. package/lib/components/index.d.ts +3 -0
  28. package/lib/components/rsl-ionic-crud.component/rsl-ionic-crud.component.d.ts +69 -0
  29. package/lib/components/rsl-ionic-data-table/rsl-ionic-data-table.component.d.ts +66 -0
  30. package/lib/components/rsl-ionic-grid/rsl-ionic-grid.component.d.ts +58 -0
  31. package/lib/decorators/index.d.ts +2 -0
  32. package/lib/decorators/ionic-datatable-layout.d.ts +7 -0
  33. package/lib/decorators/ionic-list.decorator.d.ts +2 -0
  34. package/lib/interfaces/index.d.ts +1 -0
  35. package/lib/interfaces/ionic-list-layout-config.d.ts +8 -0
  36. package/lib/ionic-dialog.service.d.ts +10 -0
  37. package/lib/rsl-ionic-module.module.d.ts +13 -0
  38. package/lib/translate.extension.d.ts +17 -0
  39. package/lib/types/index.d.ts +1 -0
  40. package/lib/types/repeat/repeat-section.type.d.ts +51 -0
  41. package/lib/validators/index.d.ts +1 -0
  42. package/lib/validators/must-match.d.ts +6 -0
  43. package/lib/wrappers/accordion-wrapper.component.d.ts +6 -0
  44. package/lib/wrappers/index.d.ts +2 -0
  45. package/lib/wrappers/panel-wrapper.component.d.ts +6 -0
  46. package/lib/wrappers/wrappers.module.d.ts +13 -0
  47. package/package.json +31 -0
  48. package/public-api.d.ts +8 -0
@@ -0,0 +1,1251 @@
1
+ import * as i3$1 from '@angular/common';
2
+ import { CommonModule } from '@angular/common';
3
+ import * as i0 from '@angular/core';
4
+ import { Injectable, NgModule, Component, ViewChild, Input } from '@angular/core';
5
+ import * as i1 from '@angular/forms';
6
+ import { ReactiveFormsModule, UntypedFormGroup, UntypedFormControl } from '@angular/forms';
7
+ import * as i1$1 from '@angular/router';
8
+ import { UrlSegment, NavigationStart } from '@angular/router';
9
+ import * as i6$1 from '@ngx-formly/core/json-schema';
10
+ import * as i2 from '@ngx-translate/core';
11
+ import { TranslateModule, TranslateService } from '@ngx-translate/core';
12
+ import * as _ from 'lodash';
13
+ import { Observable, from } from 'rxjs';
14
+ import * as i4 from '@ionic/angular';
15
+ import { IonicModule } from '@ionic/angular';
16
+ import * as i6 from '@ngx-formly/core';
17
+ import { FormlyModule, FORMLY_CONFIG, FieldArrayType, FieldWrapper } from '@ngx-formly/core';
18
+ import { FormlyIonicModule } from '@ngx-formly/ionic';
19
+ import * as i6$2 from '@swimlane/ngx-datatable';
20
+ import { NgxDatatableModule, ColumnMode, SelectionType } from '@swimlane/ngx-datatable';
21
+ import { readFileAsync, getValueFromJsonData, GridLayoutFormat } from '@rosoftlab/core';
22
+ import * as i3 from 'ngx-filesaver';
23
+ import * as XLSX from 'xlsx';
24
+ import * as jsonLogic from 'json-logic-js/logic.js';
25
+
26
+ class IonicDialogService {
27
+ constructor(alertController) {
28
+ this.alertController = alertController;
29
+ }
30
+ async confirm(message, title, confirmButtonText = 'Delete', cancelButtonText = 'Cancel') {
31
+ let choice;
32
+ const alert = await this.alertController.create({
33
+ header: title,
34
+ subHeader: message,
35
+ buttons: [{
36
+ text: cancelButtonText,
37
+ handler: () => {
38
+ alert.dismiss(false);
39
+ return false;
40
+ }
41
+ }, {
42
+ text: confirmButtonText,
43
+ handler: () => {
44
+ alert.dismiss(true);
45
+ return true;
46
+ }
47
+ }]
48
+ });
49
+ await alert.present();
50
+ await alert.onDidDismiss().then((data) => {
51
+ choice = data;
52
+ });
53
+ return choice;
54
+ }
55
+ async showSaveMessage(message, title) {
56
+ const alert = await this.alertController.create({
57
+ header: title,
58
+ subHeader: message,
59
+ buttons: ['OK']
60
+ });
61
+ await alert.present();
62
+ }
63
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: IonicDialogService, deps: [{ token: i4.AlertController }], target: i0.ɵɵFactoryTarget.Injectable }); }
64
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: IonicDialogService, providedIn: 'root' }); }
65
+ }
66
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: IonicDialogService, decorators: [{
67
+ type: Injectable,
68
+ args: [{
69
+ providedIn: 'root'
70
+ }]
71
+ }], ctorParameters: function () { return [{ type: i4.AlertController }]; } });
72
+
73
+ class TranslateExtension {
74
+ constructor(translate) {
75
+ this.translate = translate;
76
+ }
77
+ prePopulate(field) {
78
+ const props = field.props || {};
79
+ if (!props['translate'] || props['_translated']) {
80
+ return;
81
+ }
82
+ props['_translated'] = true;
83
+ field.expressions = {
84
+ ...(field.expressions || {}),
85
+ 'props.label': this.translate.stream(props.label),
86
+ };
87
+ if (props.placeholder) {
88
+ field.expressions = {
89
+ ...(field.expressions || {}),
90
+ 'props.placeholder': this.translate.stream(props.placeholder)
91
+ };
92
+ }
93
+ if (props.description) {
94
+ field.expressions = {
95
+ ...(field.expressions || {}),
96
+ 'props.description': this.translate.stream(props.description)
97
+ };
98
+ }
99
+ }
100
+ }
101
+ function registerTranslateExtension(translate) {
102
+ return {
103
+ validationMessages: [
104
+ {
105
+ name: 'required',
106
+ message(error, field) {
107
+ // console.log(field);
108
+ return translate.stream('General.Field.Required', { field: field.props.label });
109
+ },
110
+ },
111
+ ],
112
+ extensions: [
113
+ {
114
+ name: 'translate',
115
+ extension: new TranslateExtension(translate),
116
+ }
117
+ ],
118
+ };
119
+ }
120
+
121
+ const COMMON_MODULES$1 = [
122
+ CommonModule,
123
+ IonicModule,
124
+ ReactiveFormsModule,
125
+ FormlyIonicModule,
126
+ NgxDatatableModule
127
+ ];
128
+ class WrappersModule {
129
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: WrappersModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
130
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.1", ngImport: i0, type: WrappersModule, imports: [CommonModule,
131
+ IonicModule,
132
+ ReactiveFormsModule,
133
+ FormlyIonicModule,
134
+ NgxDatatableModule, TranslateModule], exports: [CommonModule,
135
+ IonicModule,
136
+ ReactiveFormsModule,
137
+ FormlyIonicModule,
138
+ NgxDatatableModule, FormlyModule,
139
+ TranslateModule] }); }
140
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: WrappersModule, providers: [
141
+ { provide: FORMLY_CONFIG, multi: true, useFactory: registerTranslateExtension, deps: [TranslateService] },
142
+ ], imports: [COMMON_MODULES$1, TranslateModule, CommonModule,
143
+ IonicModule,
144
+ ReactiveFormsModule,
145
+ FormlyIonicModule,
146
+ NgxDatatableModule, FormlyModule,
147
+ TranslateModule] }); }
148
+ }
149
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: WrappersModule, decorators: [{
150
+ type: NgModule,
151
+ args: [{
152
+ imports: [
153
+ ...COMMON_MODULES$1,
154
+ TranslateModule
155
+ ],
156
+ providers: [
157
+ { provide: FORMLY_CONFIG, multi: true, useFactory: registerTranslateExtension, deps: [TranslateService] },
158
+ ],
159
+ exports: [
160
+ ...COMMON_MODULES$1,
161
+ FormlyModule,
162
+ TranslateModule
163
+ ],
164
+ }]
165
+ }] });
166
+
167
+ class RepeatTypeComponent extends FieldArrayType {
168
+ constructor(dialogService, translate, fileSaverService) {
169
+ super();
170
+ this.dialogService = dialogService;
171
+ this.translate = translate;
172
+ this.fileSaverService = fileSaverService;
173
+ this.data = null;
174
+ this.serach = null;
175
+ this.showSerach = false;
176
+ this.filterValue = null;
177
+ this.importDataProp = null;
178
+ this.exportDataProp = null;
179
+ this.deleteMessage = this.translate.instant("General.Delete.Question");
180
+ this.deleteButton = this.translate.instant("General.Delete.Button");
181
+ this.cancelButton = this.translate.instant("General.Cancel.Button");
182
+ }
183
+ remove(i, { markAsDirty } = { markAsDirty: true }) {
184
+ this.dialogService.confirm(this.deleteMessage, null, this.deleteButton, this.cancelButton).then((value) => {
185
+ if (value.data) {
186
+ var onDelete = this.field.props['onDelete'];
187
+ if (onDelete) {
188
+ onDelete(this.field.fieldGroup[i].model).subscribe(() => {
189
+ super.remove(i);
190
+ });
191
+ }
192
+ super.remove(i);
193
+ }
194
+ });
195
+ }
196
+ ngOnInit() {
197
+ this.typeKey = this.field.key;
198
+ this.serach = this.props['search'];
199
+ this.exportDataProp = this.props['export'] || null;
200
+ this.importDataProp = this.props['import'] || null;
201
+ if (this.serach) {
202
+ this.showSerach = this.serach.showSerach;
203
+ }
204
+ }
205
+ postPopulate(field) {
206
+ if (this.showSerach) {
207
+ this.data = field.fieldGroup;
208
+ if (this.filterValue) {
209
+ this.field.fieldGroup = this.data.filter(f => f.formControl.value[this.serach.searchProp].toLowerCase().includes(this.filterValue));
210
+ }
211
+ }
212
+ }
213
+ handleChange(event) {
214
+ if (this.showSerach) {
215
+ if (this.data == null && this.field.fieldGroup !== null) {
216
+ this.data = this.field.fieldGroup;
217
+ }
218
+ this.filterValue = event.target.value.toLowerCase();
219
+ this.field.fieldGroup = this.data.filter(f => f.formControl.value[this.serach.searchProp].toLowerCase().includes(this.filterValue));
220
+ }
221
+ }
222
+ importData() {
223
+ this.fileInput.nativeElement.click();
224
+ }
225
+ async handleImportFile(event) {
226
+ const file = event.target.files[0];
227
+ if (file) {
228
+ try {
229
+ const fileContents = await readFileAsync(file);
230
+ // Handle the file contents here (e.g., display or process the data)
231
+ const wb = XLSX.read(fileContents); //, { type: 'binary' });
232
+ const wsname = wb.SheetNames[0];
233
+ const ws = wb.Sheets[wsname];
234
+ const excelData = XLSX.utils.sheet_to_json(ws); //, { header: 1 });
235
+ excelData.forEach(element => {
236
+ const jsonX = getValueFromJsonData(element, this.importDataProp.keyProp);
237
+ const idx = this.field.parent.model[this.typeKey].findIndex(f => f[this.importDataProp.keyProp] === jsonX);
238
+ if (idx >= 0) {
239
+ const existingdata = this.field.parent.model[this.typeKey][idx];
240
+ for (const prop of this.importDataProp.propertiesToImport) {
241
+ const jsonVal = getValueFromJsonData(element, prop);
242
+ if (existingdata[prop] !== jsonVal) {
243
+ var fieldControl = this.field.fieldGroup[idx].formControl;
244
+ fieldControl.controls[prop].setValue(jsonVal);
245
+ }
246
+ }
247
+ }
248
+ else {
249
+ super.add(null, element);
250
+ }
251
+ });
252
+ }
253
+ catch (error) {
254
+ console.error('Error reading the file:', error);
255
+ }
256
+ }
257
+ }
258
+ exportData() {
259
+ // Filter the data to include only the specified properties
260
+ const filteredData = this.field.parent.model[this.typeKey].map(item => {
261
+ const filteredItem = {};
262
+ for (const prop of this.exportDataProp.propertiesToExport) {
263
+ filteredItem[prop] = item[prop];
264
+ }
265
+ return filteredItem;
266
+ });
267
+ const ws = XLSX.utils.json_to_sheet(filteredData);
268
+ const wb = XLSX.utils.book_new();
269
+ XLSX.utils.book_append_sheet(wb, ws, this.exportDataProp.sheetName);
270
+ const excelBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
271
+ const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
272
+ this.fileSaverService.save(blob, this.exportDataProp.fileName);
273
+ }
274
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: RepeatTypeComponent, deps: [{ token: IonicDialogService }, { token: i2.TranslateService }, { token: i3.FileSaverService }], target: i0.ɵɵFactoryTarget.Component }); }
275
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.1", type: RepeatTypeComponent, isStandalone: true, selector: "formly-repeat-section", viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<ion-header [translucent]=\"true\">\r\n <ion-toolbar>\r\n <ng-container [ngTemplateOutlet]=\"header\"></ng-container>\r\n </ion-toolbar>\r\n <ng-container [ngTemplateOutlet]=\"search\"></ng-container>\r\n</ion-header>\r\n\r\n<ng-template #header>\r\n <ion-title class=\"ion-text-left\">{{props.label}}</ion-title>\r\n\r\n <ion-button slot=\"end\" (click)=\"exportData()\" fill=\"clear\" [disabled]=\"props.disabled\" *ngIf=\"exportDataProp\">\r\n <ion-icon name=\"cloud-download-outline\"></ion-icon>\r\n </ion-button>\r\n\r\n <ion-button slot=\"end\" (click)=\"importData()\" fill=\"clear\" [disabled]=\"props.disabled\" *ngIf=\"importDataProp\">\r\n <ion-icon name=\"cloud-upload-outline\"></ion-icon>\r\n </ion-button>\r\n <input #fileInput type=\"file\" style=\"display: none\" accept=\".xlsx,.xls,.csv\" (change)=\"handleImportFile($event)\">\r\n\r\n <ion-button slot=\"end\" (click)=\"add()\" fill=\"clear\" [disabled]=\"props.disabled\">\r\n <ion-icon size=\"large\" name=\"add\"></ion-icon>\r\n </ion-button>\r\n</ng-template>\r\n\r\n\r\n<ion-list lines=\"full\">\r\n <ion-item *ngFor=\"let field of field.fieldGroup; let i = index\" class=\"row align-items-baseline\">\r\n <formly-field class=\"formly-ion-list-item\" [field]=\"field\"></formly-field>\r\n <ion-button [disabled]=\"props.disabled\" color=\"danger\" slot=\"end\" (click)='remove(i)'>\r\n <ion-icon slot=\"icon-only\" name=\"trash\"></ion-icon>\r\n </ion-button>\r\n </ion-item>\r\n</ion-list>\r\n\r\n\r\n<ng-template #search>\r\n <ion-toolbar *ngIf=\"showSerach\">\r\n <ion-searchbar [debounce]=\"1000\" (ionChange)=\"handleChange($event)\"></ion-searchbar>\r\n </ion-toolbar>\r\n</ng-template>", styles: [".formly-ion-list-item{display:inline;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: WrappersModule }, { kind: "directive", type: i3$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i4.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: i4.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i4.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i4.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i4.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i4.IonSearchbar, selector: "ion-searchbar", inputs: ["animated", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "mode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value"] }, { kind: "component", type: i4.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i4.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i4.TextValueAccessor, selector: "ion-input:not([type=number]),ion-textarea,ion-searchbar" }, { kind: "component", type: i6.FormlyField, selector: "formly-field", inputs: ["field"] }] }); }
276
+ }
277
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: RepeatTypeComponent, decorators: [{
278
+ type: Component,
279
+ args: [{ standalone: true, selector: 'formly-repeat-section', imports: [
280
+ WrappersModule
281
+ ], template: "<ion-header [translucent]=\"true\">\r\n <ion-toolbar>\r\n <ng-container [ngTemplateOutlet]=\"header\"></ng-container>\r\n </ion-toolbar>\r\n <ng-container [ngTemplateOutlet]=\"search\"></ng-container>\r\n</ion-header>\r\n\r\n<ng-template #header>\r\n <ion-title class=\"ion-text-left\">{{props.label}}</ion-title>\r\n\r\n <ion-button slot=\"end\" (click)=\"exportData()\" fill=\"clear\" [disabled]=\"props.disabled\" *ngIf=\"exportDataProp\">\r\n <ion-icon name=\"cloud-download-outline\"></ion-icon>\r\n </ion-button>\r\n\r\n <ion-button slot=\"end\" (click)=\"importData()\" fill=\"clear\" [disabled]=\"props.disabled\" *ngIf=\"importDataProp\">\r\n <ion-icon name=\"cloud-upload-outline\"></ion-icon>\r\n </ion-button>\r\n <input #fileInput type=\"file\" style=\"display: none\" accept=\".xlsx,.xls,.csv\" (change)=\"handleImportFile($event)\">\r\n\r\n <ion-button slot=\"end\" (click)=\"add()\" fill=\"clear\" [disabled]=\"props.disabled\">\r\n <ion-icon size=\"large\" name=\"add\"></ion-icon>\r\n </ion-button>\r\n</ng-template>\r\n\r\n\r\n<ion-list lines=\"full\">\r\n <ion-item *ngFor=\"let field of field.fieldGroup; let i = index\" class=\"row align-items-baseline\">\r\n <formly-field class=\"formly-ion-list-item\" [field]=\"field\"></formly-field>\r\n <ion-button [disabled]=\"props.disabled\" color=\"danger\" slot=\"end\" (click)='remove(i)'>\r\n <ion-icon slot=\"icon-only\" name=\"trash\"></ion-icon>\r\n </ion-button>\r\n </ion-item>\r\n</ion-list>\r\n\r\n\r\n<ng-template #search>\r\n <ion-toolbar *ngIf=\"showSerach\">\r\n <ion-searchbar [debounce]=\"1000\" (ionChange)=\"handleChange($event)\"></ion-searchbar>\r\n </ion-toolbar>\r\n</ng-template>", styles: [".formly-ion-list-item{display:inline;width:100%}\n"] }]
282
+ }], ctorParameters: function () { return [{ type: IonicDialogService }, { type: i2.TranslateService }, { type: i3.FileSaverService }]; }, propDecorators: { fileInput: [{
283
+ type: ViewChild,
284
+ args: ['fileInput']
285
+ }] } });
286
+
287
+ function fieldMatchValidator(control) {
288
+ const { password, confirmPassword } = control.value;
289
+ // avoid displaying the message error when values are empty
290
+ if (!confirmPassword || !password) {
291
+ return null;
292
+ }
293
+ if (confirmPassword === password) {
294
+ return null;
295
+ }
296
+ return { fieldMatch: { message: 'Fields.Not.Matching' } };
297
+ }
298
+
299
+ class AccordionWrapperComponent extends FieldWrapper {
300
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: AccordionWrapperComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
301
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.1", type: AccordionWrapperComponent, isStandalone: true, selector: "formly-accordion-panel", usesInheritance: true, ngImport: i0, template: `
302
+
303
+ <ion-accordion-group [value]="['first']">
304
+ <ion-accordion value="first">
305
+ <ion-item slot="header">
306
+ <ion-card-title>{{ props.label}}</ion-card-title>
307
+ </ion-item>
308
+ <div class="ion-padding" slot="content">
309
+ <ng-container #fieldComponent></ng-container>
310
+ </div>
311
+ </ion-accordion>
312
+ </ion-accordion-group>
313
+
314
+
315
+
316
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: WrappersModule }, { kind: "component", type: i4.IonAccordion, selector: "ion-accordion", inputs: ["disabled", "mode", "readonly", "toggleIcon", "toggleIconSlot", "value"] }, { kind: "component", type: i4.IonAccordionGroup, selector: "ion-accordion-group", inputs: ["animated", "disabled", "expand", "mode", "multiple", "readonly", "value"] }, { kind: "component", type: i4.IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: i4.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }] }); }
317
+ }
318
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: AccordionWrapperComponent, decorators: [{
319
+ type: Component,
320
+ args: [{
321
+ standalone: true,
322
+ // eslint-disable-next-line @angular-eslint/component-selector
323
+ selector: 'formly-accordion-panel',
324
+ template: `
325
+
326
+ <ion-accordion-group [value]="['first']">
327
+ <ion-accordion value="first">
328
+ <ion-item slot="header">
329
+ <ion-card-title>{{ props.label}}</ion-card-title>
330
+ </ion-item>
331
+ <div class="ion-padding" slot="content">
332
+ <ng-container #fieldComponent></ng-container>
333
+ </div>
334
+ </ion-accordion>
335
+ </ion-accordion-group>
336
+
337
+
338
+
339
+ `,
340
+ imports: [WrappersModule]
341
+ }]
342
+ }] });
343
+
344
+ class PanelWrapperComponent extends FieldWrapper {
345
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: PanelWrapperComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
346
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.1", type: PanelWrapperComponent, isStandalone: true, selector: "formly-wrapper-panel", usesInheritance: true, ngImport: i0, template: `
347
+ <ion-card>
348
+ <ion-card-header>
349
+ <ion-card-title>{{ props.label}}</ion-card-title>
350
+ </ion-card-header>
351
+ <ion-card-content>
352
+ <ng-container #fieldComponent></ng-container>
353
+ </ion-card-content>
354
+ </ion-card>
355
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: WrappersModule }, { kind: "component", type: i4.IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: i4.IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: i4.IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: i4.IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }] }); }
356
+ }
357
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: PanelWrapperComponent, decorators: [{
358
+ type: Component,
359
+ args: [{
360
+ standalone: true,
361
+ selector: 'formly-wrapper-panel',
362
+ template: `
363
+ <ion-card>
364
+ <ion-card-header>
365
+ <ion-card-title>{{ props.label}}</ion-card-title>
366
+ </ion-card-header>
367
+ <ion-card-content>
368
+ <ng-container #fieldComponent></ng-container>
369
+ </ion-card-content>
370
+ </ion-card>
371
+ `,
372
+ imports: [WrappersModule]
373
+ }]
374
+ }] });
375
+
376
+ const COMMON_MODULES = [
377
+ CommonModule,
378
+ IonicModule,
379
+ ReactiveFormsModule,
380
+ FormlyIonicModule,
381
+ NgxDatatableModule
382
+ ];
383
+ class RslIonicModuleModule {
384
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: RslIonicModuleModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
385
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.1", ngImport: i0, type: RslIonicModuleModule, imports: [CommonModule,
386
+ IonicModule,
387
+ ReactiveFormsModule,
388
+ FormlyIonicModule,
389
+ NgxDatatableModule, TranslateModule, i6.FormlyModule], exports: [CommonModule,
390
+ IonicModule,
391
+ ReactiveFormsModule,
392
+ FormlyIonicModule,
393
+ NgxDatatableModule, FormlyModule,
394
+ TranslateModule] }); }
395
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: RslIonicModuleModule, providers: [
396
+ IonicDialogService,
397
+ { provide: FORMLY_CONFIG, multi: true, useFactory: registerTranslateExtension, deps: [TranslateService] },
398
+ ], imports: [COMMON_MODULES, TranslateModule,
399
+ FormlyModule.forRoot({
400
+ types: [{ name: 'repeat', component: RepeatTypeComponent }],
401
+ validators: [{ name: 'fieldMatch', validation: fieldMatchValidator }],
402
+ wrappers: [
403
+ { name: 'panel', component: PanelWrapperComponent },
404
+ { name: 'accordion', component: AccordionWrapperComponent }
405
+ ],
406
+ validationMessages: [
407
+ { name: 'required', message: 'This field is required' },
408
+ ],
409
+ }), CommonModule,
410
+ IonicModule,
411
+ ReactiveFormsModule,
412
+ FormlyIonicModule,
413
+ NgxDatatableModule, FormlyModule,
414
+ TranslateModule] }); }
415
+ }
416
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: RslIonicModuleModule, decorators: [{
417
+ type: NgModule,
418
+ args: [{
419
+ imports: [
420
+ ...COMMON_MODULES,
421
+ TranslateModule,
422
+ FormlyModule.forRoot({
423
+ types: [{ name: 'repeat', component: RepeatTypeComponent }],
424
+ validators: [{ name: 'fieldMatch', validation: fieldMatchValidator }],
425
+ wrappers: [
426
+ { name: 'panel', component: PanelWrapperComponent },
427
+ { name: 'accordion', component: AccordionWrapperComponent }
428
+ ],
429
+ validationMessages: [
430
+ { name: 'required', message: 'This field is required' },
431
+ ],
432
+ }),
433
+ ],
434
+ providers: [
435
+ IonicDialogService,
436
+ { provide: FORMLY_CONFIG, multi: true, useFactory: registerTranslateExtension, deps: [TranslateService] },
437
+ ],
438
+ exports: [
439
+ ...COMMON_MODULES,
440
+ FormlyModule,
441
+ TranslateModule
442
+ ],
443
+ }]
444
+ }] });
445
+
446
+ class GenericIonicCrudComponent {
447
+ //#endregion
448
+ constructor(fb, router, route, dialogService, translate, location, injector, formlyJsonschema) {
449
+ this.fb = fb;
450
+ this.router = router;
451
+ this.route = route;
452
+ this.dialogService = dialogService;
453
+ this.translate = translate;
454
+ this.location = location;
455
+ this.injector = injector;
456
+ this.formlyJsonschema = formlyJsonschema;
457
+ this.isLoading = true;
458
+ this.changeUrlRoute = true;
459
+ this.options = {};
460
+ const SERVICE_TOKEN = route.snapshot.data['requiredService'];
461
+ this.modelService = this.injector.get(SERVICE_TOKEN);
462
+ this.modelService = this.injector.get(SERVICE_TOKEN);
463
+ this.confirmQuestion = this.translate.instant('General.Discard.Question');
464
+ this.confirmButton = this.translate.instant('General.Discard.ConfirmButton');
465
+ this.saveMessage = this.translate.instant('General.Save.Message');
466
+ }
467
+ ionViewWillLeave() {
468
+ this.options.resetModel();
469
+ this.baseForm.reset();
470
+ }
471
+ afterSave(model) {
472
+ return new Observable((observer) => {
473
+ observer.next(model);
474
+ observer.complete();
475
+ });
476
+ }
477
+ beforeSave(model) {
478
+ return new Observable((observer) => {
479
+ observer.next(model);
480
+ observer.complete();
481
+ });
482
+ }
483
+ ngOnInit() {
484
+ this.initForm();
485
+ }
486
+ initForm(customInclude = '', newModelId = null, model = null) {
487
+ if (model === null) {
488
+ this.modelId = this.route.snapshot.paramMap.get('id') ?? newModelId;
489
+ this.isEdit = false;
490
+ if (this.modelId) {
491
+ this.modelService.get(this.modelId, customInclude).subscribe((value) => {
492
+ this.isEdit = true;
493
+ this.generateForm(value);
494
+ });
495
+ }
496
+ else {
497
+ if (this.changeUrlRoute) {
498
+ const addUrl = this.router.createUrlTree([]).toString();
499
+ this.editRoute = this.router.createUrlTree([addUrl.replace('add', 'edit')]).toString();
500
+ }
501
+ // }
502
+ this.generateForm(this.modelService.newModel());
503
+ }
504
+ }
505
+ else {
506
+ this.modelId = model.id;
507
+ this.isEdit = true;
508
+ this.generateForm(model);
509
+ }
510
+ }
511
+ generateForm(model) {
512
+ this.isLoading = false;
513
+ this.modelId = model.id;
514
+ this.model = model;
515
+ this.origModel = _.cloneDeep(model);
516
+ ;
517
+ this.title = this.model.modelConfig.formTitle;
518
+ this.baseForm = new UntypedFormGroup({}); //= this.modelService.toFormGroup(this.fb, model);
519
+ this.afterFormGenerated();
520
+ this.fields = this.modelService.getFormlyFields(this.model);
521
+ }
522
+ afterFormGenerated() {
523
+ }
524
+ getFromGroup(formGroup = null) {
525
+ if (!formGroup)
526
+ return this.baseForm;
527
+ if (formGroup instanceof UntypedFormGroup)
528
+ return formGroup;
529
+ return this.baseForm.controls[formGroup];
530
+ }
531
+ validateAllFormFields(formGroup = null) {
532
+ const fg = this.getFromGroup(formGroup);
533
+ Object.keys(fg.controls).forEach(field => {
534
+ // console.log(field);
535
+ const control = fg.get(field);
536
+ if (control instanceof UntypedFormControl) {
537
+ control.markAsTouched({ onlySelf: true });
538
+ }
539
+ else if (control instanceof UntypedFormGroup) {
540
+ this.validateAllFormFields(control);
541
+ }
542
+ });
543
+ }
544
+ isFieldValid(field, formGroup = null) {
545
+ const fg = this.getFromGroup(formGroup);
546
+ const filedControl = fg.get(field);
547
+ return !filedControl.valid && filedControl.touched;
548
+ }
549
+ isFieldValidFromArray(arrayIndex, field, arrayName = 'formArray') {
550
+ const fieldControl = this.baseForm.get(arrayName).get([arrayIndex]).get(field);
551
+ return !fieldControl.valid && fieldControl.touched;
552
+ }
553
+ displayFieldCss(field) {
554
+ return {
555
+ 'has-error': this.isFieldValid(field),
556
+ 'has-feedback': this.isFieldValid(field)
557
+ };
558
+ }
559
+ onCancel() {
560
+ this.router.navigate([this.cancelRoute]);
561
+ }
562
+ onSave() {
563
+ this.saveModel(this.baseForm);
564
+ }
565
+ onSubmit(model) {
566
+ this.saveModel(this.baseForm);
567
+ }
568
+ saveModel(formGroup = null) {
569
+ const fg = this.getFromGroup(formGroup);
570
+ const that = this;
571
+ if (fg) {
572
+ if (fg.valid) {
573
+ this.beforeSave(this.model).subscribe(_ => {
574
+ this.modelService.save(this.model, this.modelId, this.origModel).subscribe((newModel) => {
575
+ this.model = newModel;
576
+ this.modelId = newModel.id;
577
+ if (this.editRoute) {
578
+ this.isEdit = true;
579
+ if (this.changeUrlRoute) {
580
+ const url = this.router.createUrlTree([this.editRoute, this.modelId]).toString();
581
+ this.location.replaceState(url);
582
+ }
583
+ }
584
+ this.afterSave(newModel).subscribe((val) => {
585
+ from(this.dialogService.showSaveMessage(this.saveMessage)).subscribe(d => {
586
+ this.options.updateInitialValue();
587
+ fg.markAsPristine();
588
+ });
589
+ });
590
+ }, err => {
591
+ this.serverErrors(err);
592
+ });
593
+ });
594
+ }
595
+ else {
596
+ this.validateAllFormFields(formGroup);
597
+ }
598
+ }
599
+ }
600
+ serverErrors(err) {
601
+ if (err.error) {
602
+ if (err.error.errors) {
603
+ const validationErrors = err.error.errors;
604
+ if (Array.isArray(validationErrors)) {
605
+ validationErrors.forEach(prop => {
606
+ const formControl = this.baseForm.get(this.firstCharToLowerCase(prop));
607
+ if (formControl) {
608
+ // activate the error message
609
+ formControl.setErrors({
610
+ serverError: { message: validationErrors[prop].join('\n') }
611
+ });
612
+ }
613
+ });
614
+ }
615
+ else {
616
+ const keys = Object.keys(validationErrors);
617
+ keys.forEach(prop => {
618
+ const formControl = this.baseForm.get(this.firstCharToLowerCase(prop));
619
+ if (formControl) {
620
+ // activate the error message
621
+ formControl.setErrors({
622
+ serverError: { message: validationErrors[prop].join('\n') }
623
+ });
624
+ }
625
+ });
626
+ }
627
+ }
628
+ }
629
+ }
630
+ firstCharToLowerCase(str) {
631
+ if (str.length === 0) {
632
+ return str; // Return an empty string if the input is empty
633
+ }
634
+ const firstChar = str.charAt(0).toLowerCase();
635
+ const restOfString = str.slice(1);
636
+ return firstChar + restOfString;
637
+ }
638
+ async canDeactivate() {
639
+ if (!this.baseForm.dirty) {
640
+ return true;
641
+ }
642
+ var result = await this.dialogService.confirm(this.confirmQuestion, null, this.confirmButton);
643
+ return result;
644
+ }
645
+ getFiledName(filedTranslationKey) {
646
+ return { field: this.translate.instant(filedTranslationKey) };
647
+ }
648
+ getCustomErrorMessage(error, fieldLabel) {
649
+ return '';
650
+ }
651
+ getErrorMessageFromArray(arrayIndex, field, filedTranslationKey, arrayName = 'formArray') {
652
+ const fieldControl = this.baseForm.get(arrayName).get([arrayIndex]).get(field);
653
+ return this.getErrorMessageForField(fieldControl, filedTranslationKey);
654
+ }
655
+ getErrorMessage(field, filedTranslationKey, formGroup = null) {
656
+ const fg = this.getFromGroup(formGroup);
657
+ return this.getErrorMessageForField(fg.get(field), filedTranslationKey);
658
+ }
659
+ getErrorMessageForField(fieldControl, filedTranslationKey) {
660
+ const error = fieldControl.errors;
661
+ const fieldLabel = this.translate.instant(filedTranslationKey);
662
+ let rvalue = '';
663
+ if (error !== null) {
664
+ if (error['required'] === true) {
665
+ rvalue = this.translate.instant('General.Field.Required', { field: fieldLabel });
666
+ }
667
+ if (error['minlength']) {
668
+ rvalue = this.translate.instant('General.Field.MinLength', { field: fieldLabel, requiredLength: error.minlength.requiredLength });
669
+ }
670
+ if (error['email'] === true) {
671
+ rvalue = this.translate.instant('General.Field.InvalidEmail');
672
+ }
673
+ if (error['url'] === true) {
674
+ rvalue = this.translate.instant('General.Field.InvalidUrl');
675
+ }
676
+ if (error['serverError']) {
677
+ rvalue = error['serverError'];
678
+ }
679
+ if (rvalue === '') {
680
+ rvalue = this.getCustomErrorMessage(error, fieldLabel);
681
+ }
682
+ }
683
+ return rvalue;
684
+ }
685
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: GenericIonicCrudComponent, deps: [{ token: i1.UntypedFormBuilder }, { token: i1$1.Router }, { token: i1$1.ActivatedRoute }, { token: IonicDialogService }, { token: i2.TranslateService }, { token: i3$1.Location }, { token: i0.Injector }, { token: i6$1.FormlyJsonschema }], target: i0.ɵɵFactoryTarget.Component }); }
686
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.1", type: GenericIonicCrudComponent, isStandalone: true, selector: "rslc-ionic-crud", ngImport: i0, template: "<ion-header [translucent]=\"true\">\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-menu-button></ion-menu-button>\n <ion-back-button></ion-back-button>\n </ion-buttons>\n <ng-container [ngTemplateOutlet]=\"header\"></ng-container>\n </ion-toolbar>\n</ion-header>\n\n<ion-content [fullscreen]=\"true\">\n <ng-container *ngIf=\"!isLoading\">\n <form [formGroup]=\"baseForm\" (ngSubmit)=\"onSubmit(model)\">\n <formly-form [form]=\"baseForm\" [fields]=\"fields\" [model]=\"model\" [options]=\"options\"></formly-form>\n </form>\n </ng-container>\n</ion-content>\n\n<ng-template #header>\n <ion-title class=\"ion-text-center\">{{title |translate}}</ion-title>\n <ion-button *ngIf=\"!isLoading\" slot=\"end\" fill=\"clear\" (click)=\"onSave()\"\n [disabled]=\"baseForm.invalid || !baseForm.dirty\">\n <ion-icon size=\"large\" name=\"save\"></ion-icon>\n </ion-button>\n</ng-template>", styles: [""], dependencies: [{ kind: "ngmodule", type: RslIonicModuleModule }, { kind: "directive", type: i3$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i4.IonBackButton, selector: "ion-back-button", inputs: ["color", "defaultHref", "disabled", "icon", "mode", "routerAnimation", "text", "type"] }, { kind: "component", type: i4.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: i4.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i4.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i4.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i4.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i4.IonMenuButton, selector: "ion-menu-button", inputs: ["autoHide", "color", "disabled", "menu", "mode", "type"] }, { kind: "component", type: i4.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i4.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i4.IonBackButtonDelegate, selector: "ion-back-button", inputs: ["defaultHref", "routerAnimation"] }, { 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: i6.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] }); }
687
+ }
688
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: GenericIonicCrudComponent, decorators: [{
689
+ type: Component,
690
+ args: [{ standalone: true, selector: 'rslc-ionic-crud', imports: [RslIonicModuleModule], template: "<ion-header [translucent]=\"true\">\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-menu-button></ion-menu-button>\n <ion-back-button></ion-back-button>\n </ion-buttons>\n <ng-container [ngTemplateOutlet]=\"header\"></ng-container>\n </ion-toolbar>\n</ion-header>\n\n<ion-content [fullscreen]=\"true\">\n <ng-container *ngIf=\"!isLoading\">\n <form [formGroup]=\"baseForm\" (ngSubmit)=\"onSubmit(model)\">\n <formly-form [form]=\"baseForm\" [fields]=\"fields\" [model]=\"model\" [options]=\"options\"></formly-form>\n </form>\n </ng-container>\n</ion-content>\n\n<ng-template #header>\n <ion-title class=\"ion-text-center\">{{title |translate}}</ion-title>\n <ion-button *ngIf=\"!isLoading\" slot=\"end\" fill=\"clear\" (click)=\"onSave()\"\n [disabled]=\"baseForm.invalid || !baseForm.dirty\">\n <ion-icon size=\"large\" name=\"save\"></ion-icon>\n </ion-button>\n</ng-template>" }]
691
+ }], ctorParameters: function () { return [{ type: i1.UntypedFormBuilder }, { type: i1$1.Router }, { type: i1$1.ActivatedRoute }, { type: IonicDialogService }, { type: i2.TranslateService }, { type: i3$1.Location }, { type: i0.Injector }, { type: i6$1.FormlyJsonschema }]; } });
692
+
693
+ class RslIonicDataTableComponent {
694
+ constructor(router, route, translate, location, injector, navCtrl, dialogService, el) {
695
+ this.router = router;
696
+ this.route = route;
697
+ this.translate = translate;
698
+ this.location = location;
699
+ this.injector = injector;
700
+ this.navCtrl = navCtrl;
701
+ this.dialogService = dialogService;
702
+ this.el = el;
703
+ this.data = [];
704
+ this.pageIndex = 1;
705
+ this.pageSize = 30;
706
+ this.columns = [];
707
+ this.allColumns = [];
708
+ this.ColumnMode = ColumnMode;
709
+ this.SelectionType = SelectionType;
710
+ this.headerHeight = 50;
711
+ this.rowHeight = 50;
712
+ }
713
+ ngOnInit() {
714
+ this.setValueFromSnapshot(this, this.route.snapshot, 'showSerach', false);
715
+ this.setValueFromSnapshot(this, this.route.snapshot, 'searchFields', null);
716
+ this.setValueFromSnapshot(this, this.route.snapshot, 'customInclude', null);
717
+ this.setValueFromSnapshot(this, this.route.snapshot, 'defaultSort', null);
718
+ this.setValueFromSnapshot(this, this.route.snapshot, 'defaultSortDirection', '');
719
+ this.setValueFromSnapshot(this, this.route.snapshot, 'deletePropertyName', 'name');
720
+ this.setValueFromSnapshot(this, this.route.snapshot, 'defaultFilter', null);
721
+ this.setValueFromSnapshot(this, this.route.snapshot, 'showHeader', true);
722
+ this.setValueFromSnapshot(this, this.route.snapshot, 'deleteDisableRule', null);
723
+ this.setValueFromSnapshot(this, this.route.snapshot, 'hasAdd', true);
724
+ this.setValueFromSnapshot(this, this.route.snapshot, 'canDelete', true);
725
+ this.setValueFromSnapshot(this, this.route.snapshot, 'canEdit', true);
726
+ if (!this.modelService) {
727
+ const SERVICE_TOKEN = this.route.snapshot.data['requiredService'];
728
+ this.modelService = this.injector.get(SERVICE_TOKEN);
729
+ }
730
+ this.model = this.modelService.newModel();
731
+ this.title = this.model.modelConfig.formTitle;
732
+ this.getListLayout();
733
+ const currentUrlSegments = this.router.url.split('/').map(segment => new UrlSegment(segment, {}));
734
+ this.basePath = currentUrlSegments.map(segment => segment.path).join('/');
735
+ this.router.events.subscribe(event => {
736
+ if (event instanceof NavigationStart) {
737
+ // Navigation to another page is about to occur
738
+ this.data = [];
739
+ this.pageIndex = 1;
740
+ // Perform actions or update component as needed
741
+ }
742
+ });
743
+ // this.isLoading = true;
744
+ // this.onScroll(0);
745
+ }
746
+ setValueFromSnapshot(component, snapshot, key, defaultValue) {
747
+ if (component[key] === undefined) {
748
+ let dataFromSnapshot = snapshot.data[key];
749
+ if (dataFromSnapshot === null || dataFromSnapshot === undefined) {
750
+ dataFromSnapshot = snapshot.params[key];
751
+ }
752
+ component[key] = dataFromSnapshot !== undefined ? dataFromSnapshot : defaultValue;
753
+ }
754
+ }
755
+ onScroll(offsetY) {
756
+ if (offsetY) {
757
+ if (this.oldOffsetY !== offsetY) {
758
+ this.oldOffsetY = offsetY;
759
+ const viewHeight = this.el.nativeElement.getBoundingClientRect().height - this.headerHeight;
760
+ if (!this.isLoading && offsetY + viewHeight >= this.data.length * this.rowHeight) {
761
+ // total number of results to load
762
+ let limit = this.pageSize;
763
+ // check if we haven't fetched any results yet
764
+ if (this.data.length === 0) {
765
+ // calculate the number of rows that fit within viewport
766
+ const pageSize = Math.ceil(viewHeight / this.rowHeight);
767
+ // change the limit to pageSize such that we fill the first page entirely
768
+ // (otherwise, we won't be able to scroll past it)
769
+ limit = Math.max(pageSize, this.pageSize);
770
+ }
771
+ // this.pageIndex
772
+ this.pageSize = limit;
773
+ this.loadData();
774
+ // this.loadPage(limit);
775
+ }
776
+ }
777
+ }
778
+ }
779
+ async ionViewWillEnter() {
780
+ this.data = [];
781
+ this.loadData();
782
+ }
783
+ async handleChange(event) {
784
+ this.filterValue = event.target.value.toLowerCase();
785
+ this.data = [];
786
+ this.pageIndex = 1;
787
+ this.loadData();
788
+ }
789
+ loadData(event = null) {
790
+ const filters = [];
791
+ let sorts = '';
792
+ this.isLoading = true;
793
+ if (this.defaultSort) {
794
+ if (this.defaultSortDirection === 'desc') {
795
+ sorts = '-' + this.defaultSort;
796
+ }
797
+ else {
798
+ sorts = this.defaultSort;
799
+ }
800
+ }
801
+ if (this.showSerach) {
802
+ if (this.filterValue) {
803
+ const y = '(' + this.searchFields.replace(',', '|') + ')';
804
+ filters.push(y + '@=*' + this.filterValue);
805
+ }
806
+ }
807
+ if (this.defaultFilter) {
808
+ filters.push(this.defaultFilter);
809
+ }
810
+ setTimeout(() => {
811
+ const filtersValue = filters.join(', ');
812
+ this.modelService.getAll(this.pageIndex, this.pageSize, sorts, filtersValue, this.customInclude).subscribe((response) => {
813
+ if (this.pageIndex !== response.getMeta().meta.count) {
814
+ this.pageIndex++;
815
+ }
816
+ else {
817
+ if (event)
818
+ event.target.disabled = true;
819
+ }
820
+ // if (this.filterValue)
821
+ // this.data = response.getModels();
822
+ // else
823
+ const rows = [...this.data, ...response.getModels()];
824
+ this.data = rows;
825
+ // this.data = this.data.concat();
826
+ if (event)
827
+ event.target.complete();
828
+ this.isLoading = false;
829
+ });
830
+ }, 700);
831
+ }
832
+ async handleRefresh(event) {
833
+ this.pageIndex = 1;
834
+ this.data = [];
835
+ this.loadData();
836
+ event.target.complete();
837
+ }
838
+ onAdd() {
839
+ console.log(this.basePath);
840
+ this.router.navigate([this.basePath + '/add']);
841
+ // this.navCtrl.navigateForward(this.basePath + '/add');
842
+ }
843
+ editModel(model) {
844
+ if (this.canEdit)
845
+ this.router.navigate([this.basePath + '/edit/', model.id]);
846
+ // this.navCtrl.navigateForward(this.basePath + '/edit/' + model.id);
847
+ }
848
+ getListLayout() {
849
+ if (!this.model) {
850
+ this.model = this.modelService.newModel();
851
+ }
852
+ this.allColumns = [];
853
+ this.columns = [];
854
+ this.allColumns = Reflect.getMetadata('IonicDataTableLayout', this.model).map((item) => {
855
+ if (!item.isTranslated) {
856
+ item.name = this.translate.instant(item.name);
857
+ item.isTranslated = true;
858
+ }
859
+ return item;
860
+ });
861
+ this.allColumns.sort((a, b) => a.order - b.order);
862
+ if (this.canDelete || this.canEdit) {
863
+ this.allColumns.push({
864
+ cellTemplate: this.actionsTmpl,
865
+ name: '',
866
+ cellClass: 'actions-cell',
867
+ draggable: false,
868
+ sortable: false,
869
+ visible: true
870
+ // width: 100,
871
+ // maxWidth: 100,
872
+ // minWidth: 100
873
+ });
874
+ }
875
+ this.columns = this.allColumns.filter((item) => item.visible);
876
+ // Sort the columns array by the order property
877
+ }
878
+ deleteModel(model) {
879
+ const msg = 'Do you want to delete ' + model[this.deletePropertyName] + '?';
880
+ this.dialogService.confirm(msg).then((value) => {
881
+ if (value.data) {
882
+ this.modelService.delete(model.id).subscribe(() => {
883
+ const tempData = [];
884
+ // this.selectedObject.emit(null);
885
+ this.data.map((item) => {
886
+ if (item.id !== model.id) {
887
+ tempData.push(item);
888
+ }
889
+ });
890
+ this.data = tempData;
891
+ });
892
+ }
893
+ });
894
+ }
895
+ deleteEnabled(model) {
896
+ if (this.canDelete) {
897
+ if (this.deleteDisableRule) {
898
+ return this.evaluateRule(this.deleteDisableRule, model);
899
+ }
900
+ else {
901
+ return true;
902
+ }
903
+ }
904
+ else {
905
+ return false;
906
+ }
907
+ }
908
+ evaluateRule(rules, model) {
909
+ let result = true;
910
+ rules.forEach(rule => {
911
+ let jsonRule;
912
+ if (typeof rule.rule === 'string') {
913
+ jsonRule = JSON.parse(rule.rule);
914
+ }
915
+ else {
916
+ jsonRule = rule.rule;
917
+ }
918
+ if (rule.parameters) {
919
+ const data = '{' + rule.parameters.map((item) => {
920
+ return '"' + item + '":"' + model[item] + '"';
921
+ }).join(',') + '}';
922
+ result = jsonLogic.apply(jsonRule, JSON.parse(data));
923
+ }
924
+ else {
925
+ result = jsonLogic.apply(jsonRule);
926
+ }
927
+ });
928
+ return result;
929
+ }
930
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: RslIonicDataTableComponent, deps: [{ token: i1$1.Router }, { token: i1$1.ActivatedRoute }, { token: i2.TranslateService }, { token: i3$1.Location }, { token: i0.Injector }, { token: i4.NavController }, { token: IonicDialogService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
931
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.1", type: RslIonicDataTableComponent, isStandalone: true, selector: "app-rsl-ionic-data-table", inputs: { showSerach: "showSerach", searchFields: "searchFields", customInclude: "customInclude", defaultSort: "defaultSort", defaultSortDirection: "defaultSortDirection", deletePropertyName: "deletePropertyName", defaultFilter: "defaultFilter", showHeader: "showHeader", deleteDisableRule: "deleteDisableRule", hasAdd: "hasAdd", canDelete: "canDelete", canEdit: "canEdit", model: "model", modelService: "modelService" }, viewQueries: [{ propertyName: "actionsTmpl", first: true, predicate: ["actionsTmpl"], descendants: true, static: true }], ngImport: i0, template: "<ion-header *ngIf=\"showHeader\">\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-menu-button></ion-menu-button>\n <ion-back-button></ion-back-button>\n </ion-buttons>\n <ng-container [ngTemplateOutlet]=\"header\"></ng-container>\n </ion-toolbar>\n <ng-container [ngTemplateOutlet]=\"search\"></ng-container>\n</ion-header>\n\n<ion-content [fullscreen]=\"true\">\n\n <ion-refresher slot=\"fixed\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <ngx-datatable class=\"material fullscreen rls-server-scrolling\" style=\"top: 115px\" [rows]=\"data\" [columns]=\"columns\"\n [columnMode]=\"ColumnMode.standard\" [headerHeight]=\"headerHeight\" [rowHeight]=\"rowHeight\" [scrollbarV]=\"true\"\n [loadingIndicator]=\"isLoading\" [scrollbarH]=\"true\" (scroll)=\"onScroll($event.offsetY)\"\n >\n </ngx-datatable>\n \n <ng-template #actionsTmpl let-row=\"row\" let-value=\"value\">\n <ion-button fill=\"clear\" *ngIf=\"canEdit\" (click)='editModel(row)'>\n <ion-icon slot=\"icon-only\" name=\"create\" (click)='editModel(row)'></ion-icon>\n </ion-button>\n <ion-button fill=\"clear\" *ngIf=\"deleteEnabled(row)\" (click)='deleteModel(row)'>\n <ion-icon color=\"danger\" slot=\"icon-only\" name=\"trash\" (click)='deleteModel(row)'></ion-icon>\n </ion-button>\n </ng-template>\n\n</ion-content>\n\n<ng-template #header>\n <ion-title class=\"ion-text-center\">{{title}}</ion-title>\n <ion-button slot=\"end\" (click)=\"onAdd()\" fill=\"clear\" *ngIf=\"hasAdd\">\n <ion-icon size=\"large\" name=\"add\"></ion-icon>\n </ion-button>\n</ng-template>\n\n<ng-template #search>\n <ion-toolbar *ngIf=\"showSerach\">\n <ion-searchbar [debounce]=\"1000\" (ionChange)=\"handleChange($event)\"></ion-searchbar>\n </ion-toolbar>\n</ng-template>", styles: [".rls-server-scrolling{height:calc(100vh - 110px)}::ng-deep .progress-linear{position:fixed!important;bottom:0}::ng-deep .actions-cell{padding:5px 0 0 .9rem!important}::ng-deep .align-right{text-align:right!important}\n"], dependencies: [{ kind: "ngmodule", type: RslIonicModuleModule }, { kind: "directive", type: i3$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i4.IonBackButton, selector: "ion-back-button", inputs: ["color", "defaultHref", "disabled", "icon", "mode", "routerAnimation", "text", "type"] }, { kind: "component", type: i4.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: i4.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i4.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i4.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i4.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i4.IonMenuButton, selector: "ion-menu-button", inputs: ["autoHide", "color", "disabled", "menu", "mode", "type"] }, { kind: "component", type: i4.IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: i4.IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: i4.IonSearchbar, selector: "ion-searchbar", inputs: ["animated", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "mode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value"] }, { kind: "component", type: i4.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i4.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i4.TextValueAccessor, selector: "ion-input:not([type=number]),ion-textarea,ion-searchbar" }, { kind: "directive", type: i4.IonBackButtonDelegate, selector: "ion-back-button", inputs: ["defaultHref", "routerAnimation"] }, { kind: "component", type: i6$2.DatatableComponent, selector: "ngx-datatable", inputs: ["targetMarkerTemplate", "rows", "groupRowsBy", "groupedRows", "columns", "selected", "scrollbarV", "scrollbarH", "rowHeight", "columnMode", "headerHeight", "footerHeight", "externalPaging", "externalSorting", "limit", "count", "offset", "loadingIndicator", "selectionType", "reorderable", "swapColumns", "sortType", "sorts", "cssClasses", "messages", "rowClass", "selectCheck", "displayCheck", "groupExpansionDefault", "trackByProp", "selectAllRowsOnPage", "virtualization", "treeFromRelation", "treeToRelation", "summaryRow", "summaryHeight", "summaryPosition", "rowIdentity"], outputs: ["scroll", "activate", "select", "sort", "page", "reorder", "resize", "tableContextmenu", "treeAction"] }] }); }
932
+ }
933
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: RslIonicDataTableComponent, decorators: [{
934
+ type: Component,
935
+ args: [{ standalone: true, selector: 'app-rsl-ionic-data-table', imports: [RslIonicModuleModule], template: "<ion-header *ngIf=\"showHeader\">\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-menu-button></ion-menu-button>\n <ion-back-button></ion-back-button>\n </ion-buttons>\n <ng-container [ngTemplateOutlet]=\"header\"></ng-container>\n </ion-toolbar>\n <ng-container [ngTemplateOutlet]=\"search\"></ng-container>\n</ion-header>\n\n<ion-content [fullscreen]=\"true\">\n\n <ion-refresher slot=\"fixed\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <ngx-datatable class=\"material fullscreen rls-server-scrolling\" style=\"top: 115px\" [rows]=\"data\" [columns]=\"columns\"\n [columnMode]=\"ColumnMode.standard\" [headerHeight]=\"headerHeight\" [rowHeight]=\"rowHeight\" [scrollbarV]=\"true\"\n [loadingIndicator]=\"isLoading\" [scrollbarH]=\"true\" (scroll)=\"onScroll($event.offsetY)\"\n >\n </ngx-datatable>\n \n <ng-template #actionsTmpl let-row=\"row\" let-value=\"value\">\n <ion-button fill=\"clear\" *ngIf=\"canEdit\" (click)='editModel(row)'>\n <ion-icon slot=\"icon-only\" name=\"create\" (click)='editModel(row)'></ion-icon>\n </ion-button>\n <ion-button fill=\"clear\" *ngIf=\"deleteEnabled(row)\" (click)='deleteModel(row)'>\n <ion-icon color=\"danger\" slot=\"icon-only\" name=\"trash\" (click)='deleteModel(row)'></ion-icon>\n </ion-button>\n </ng-template>\n\n</ion-content>\n\n<ng-template #header>\n <ion-title class=\"ion-text-center\">{{title}}</ion-title>\n <ion-button slot=\"end\" (click)=\"onAdd()\" fill=\"clear\" *ngIf=\"hasAdd\">\n <ion-icon size=\"large\" name=\"add\"></ion-icon>\n </ion-button>\n</ng-template>\n\n<ng-template #search>\n <ion-toolbar *ngIf=\"showSerach\">\n <ion-searchbar [debounce]=\"1000\" (ionChange)=\"handleChange($event)\"></ion-searchbar>\n </ion-toolbar>\n</ng-template>", styles: [".rls-server-scrolling{height:calc(100vh - 110px)}::ng-deep .progress-linear{position:fixed!important;bottom:0}::ng-deep .actions-cell{padding:5px 0 0 .9rem!important}::ng-deep .align-right{text-align:right!important}\n"] }]
936
+ }], ctorParameters: function () { return [{ type: i1$1.Router }, { type: i1$1.ActivatedRoute }, { type: i2.TranslateService }, { type: i3$1.Location }, { type: i0.Injector }, { type: i4.NavController }, { type: IonicDialogService }, { type: i0.ElementRef }]; }, propDecorators: { actionsTmpl: [{
937
+ type: ViewChild,
938
+ args: ['actionsTmpl', { static: true }]
939
+ }], showSerach: [{
940
+ type: Input
941
+ }], searchFields: [{
942
+ type: Input
943
+ }], customInclude: [{
944
+ type: Input
945
+ }], defaultSort: [{
946
+ type: Input
947
+ }], defaultSortDirection: [{
948
+ type: Input
949
+ }], deletePropertyName: [{
950
+ type: Input
951
+ }], defaultFilter: [{
952
+ type: Input
953
+ }], showHeader: [{
954
+ type: Input
955
+ }], deleteDisableRule: [{
956
+ type: Input
957
+ }], hasAdd: [{
958
+ type: Input
959
+ }], canDelete: [{
960
+ type: Input
961
+ }], canEdit: [{
962
+ type: Input
963
+ }], model: [{
964
+ type: Input
965
+ }], modelService: [{
966
+ type: Input
967
+ }] } });
968
+
969
+ class RslIonicGridComponent {
970
+ constructor(router, route, translate, location, injector, loadingCtrl, navCtrl, dialogService, datePipe, numberPipe, percentPipe) {
971
+ this.router = router;
972
+ this.route = route;
973
+ this.translate = translate;
974
+ this.location = location;
975
+ this.injector = injector;
976
+ this.loadingCtrl = loadingCtrl;
977
+ this.navCtrl = navCtrl;
978
+ this.dialogService = dialogService;
979
+ this.datePipe = datePipe;
980
+ this.numberPipe = numberPipe;
981
+ this.percentPipe = percentPipe;
982
+ this.data = [];
983
+ this.pageIndex = 1;
984
+ this.pageSize = 30;
985
+ }
986
+ ngOnInit() {
987
+ this.setValueFromSnapshot(this, this.route.snapshot, 'showSerach', false);
988
+ this.setValueFromSnapshot(this, this.route.snapshot, 'searchFields', null);
989
+ this.setValueFromSnapshot(this, this.route.snapshot, 'customInclude', null);
990
+ this.setValueFromSnapshot(this, this.route.snapshot, 'defaultSort', null);
991
+ this.setValueFromSnapshot(this, this.route.snapshot, 'defaultSortDirection', '');
992
+ this.setValueFromSnapshot(this, this.route.snapshot, 'deletePropertyName', 'name');
993
+ this.setValueFromSnapshot(this, this.route.snapshot, 'defaultFilter', null);
994
+ this.setValueFromSnapshot(this, this.route.snapshot, 'showHeader', true);
995
+ this.setValueFromSnapshot(this, this.route.snapshot, 'deleteDisableRule', null);
996
+ // this.showSerach = route.snapshot.data['showSerach'] || false;
997
+ // this.searchFields = this.route.snapshot.data['searchFields'] || null;
998
+ // this.customInclude = this.route.snapshot.data['customInclude'] || null;
999
+ // this.defaultSort = this.route.snapshot.data['defaultSort'] || null;
1000
+ // this.defaultSortDirection = this.route.snapshot.data['defaultSortDirection'] || '';
1001
+ // this.deletePropertyName = this.route.snapshot.data['deletePropertyName'] || 'name';
1002
+ // this.defaultFilter = this.route.snapshot.data['defaultFilter'] || null;
1003
+ if (!this.modelService) {
1004
+ const SERVICE_TOKEN = this.route.snapshot.data['requiredService'];
1005
+ this.modelService = this.injector.get(SERVICE_TOKEN);
1006
+ }
1007
+ this.model = this.modelService.newModel();
1008
+ this.title = this.model.modelConfig.formTitle;
1009
+ this.getListLayout();
1010
+ const currentUrlSegments = this.router.url.split('/').map(segment => new UrlSegment(segment, {}));
1011
+ this.basePath = currentUrlSegments.map(segment => segment.path).join('/');
1012
+ this.router.events.subscribe(event => {
1013
+ if (event instanceof NavigationStart) {
1014
+ // Navigation to another page is about to occur
1015
+ this.data = [];
1016
+ this.pageIndex = 1;
1017
+ // Perform actions or update component as needed
1018
+ }
1019
+ });
1020
+ }
1021
+ setValueFromSnapshot(component, snapshot, key, defaultValue) {
1022
+ if (component[key] === undefined) {
1023
+ let dataFromSnapshot = snapshot.data[key];
1024
+ if (!dataFromSnapshot)
1025
+ dataFromSnapshot = snapshot.params[key];
1026
+ component[key] = dataFromSnapshot !== undefined ? dataFromSnapshot : defaultValue;
1027
+ }
1028
+ }
1029
+ async ionViewWillEnter() {
1030
+ this.data = [];
1031
+ const loading = await this.loadingCtrl.create({
1032
+ message: this.translate.instant('General.Loading'),
1033
+ spinner: 'circles',
1034
+ });
1035
+ loading.present();
1036
+ this.loadData(null, null, loading);
1037
+ }
1038
+ async handleChange(event) {
1039
+ const loading = await this.loadingCtrl.create({
1040
+ message: this.translate.instant('General.Loading'),
1041
+ spinner: 'circles',
1042
+ });
1043
+ loading.present();
1044
+ const query = event.target.value.toLowerCase();
1045
+ this.pageIndex = 1;
1046
+ this.loadData(null, query, loading);
1047
+ // this.results = this.data.filter((d) => d.toLowerCase().indexOf(query) > -1);
1048
+ }
1049
+ loadData(event = null, filterValue = undefined, loading = null) {
1050
+ const filters = [];
1051
+ let sorts = '';
1052
+ if (this.defaultSort) {
1053
+ if (this.defaultSortDirection === 'desc') {
1054
+ sorts = '-' + this.defaultSort;
1055
+ }
1056
+ else {
1057
+ sorts = this.defaultSort;
1058
+ }
1059
+ }
1060
+ if (this.showSerach) {
1061
+ if (filterValue) {
1062
+ const y = '(' + this.searchFields.replace(',', '|') + ')';
1063
+ filters.push(y + '@=*' + filterValue);
1064
+ }
1065
+ }
1066
+ if (this.defaultFilter) {
1067
+ filters.push(this.defaultFilter);
1068
+ }
1069
+ setTimeout(() => {
1070
+ const filtersValue = filters.join(', ');
1071
+ this.modelService.getAll(this.pageIndex, this.pageSize, sorts, filtersValue, this.customInclude).subscribe((response) => {
1072
+ if (this.pageIndex !== response.getMeta().meta.count) {
1073
+ this.pageIndex++;
1074
+ }
1075
+ else {
1076
+ if (event)
1077
+ event.target.disabled = true;
1078
+ }
1079
+ if (filterValue || loading)
1080
+ this.data = response.getModels();
1081
+ else
1082
+ this.data = this.data.concat(response.getModels());
1083
+ if (event)
1084
+ event.target.complete();
1085
+ if (loading)
1086
+ loading.dismiss();
1087
+ });
1088
+ }, 700);
1089
+ }
1090
+ async handleRefresh(event) {
1091
+ const loading = await this.loadingCtrl.create({
1092
+ message: this.translate.instant('General.Loading'),
1093
+ spinner: 'circles',
1094
+ });
1095
+ loading.present();
1096
+ this.pageIndex = 1;
1097
+ this.loadData(null, null, loading);
1098
+ event.target.complete();
1099
+ }
1100
+ onAdd() {
1101
+ console.log(this.basePath);
1102
+ this.navCtrl.navigateForward(this.basePath + '/add');
1103
+ }
1104
+ editModel(model) {
1105
+ this.navCtrl.navigateForward(this.basePath + '/edit/' + model.id);
1106
+ }
1107
+ getListLayout() {
1108
+ if (!this.model) {
1109
+ this.model = this.modelService.newModel();
1110
+ }
1111
+ this.gridLayout = Reflect.getMetadata('IonicListLayout', this.model);
1112
+ }
1113
+ deleteModel(model) {
1114
+ const msg = 'Do you want to delete ' + model[this.deletePropertyName] + '?';
1115
+ this.dialogService.confirm(msg).then((value) => {
1116
+ if (value.data) {
1117
+ this.modelService.delete(model.id).subscribe(() => {
1118
+ const tempData = [];
1119
+ // this.selectedObject.emit(null);
1120
+ this.data.map((item) => {
1121
+ if (item.id !== model.id) {
1122
+ tempData.push(item);
1123
+ }
1124
+ });
1125
+ this.data = tempData;
1126
+ });
1127
+ }
1128
+ });
1129
+ }
1130
+ getCelValue(row, propertyName) {
1131
+ if (!row)
1132
+ return "";
1133
+ // if (propertyName == 'kompetenzenStdev')
1134
+ // console.log(propertyName);
1135
+ if (propertyName.indexOf('.') === -1) {
1136
+ var gridLayout = this.gridLayout.find(f => f.key.indexOf(propertyName) > -1);
1137
+ return this.getFormatedValue(gridLayout, row[propertyName]);
1138
+ }
1139
+ else {
1140
+ const prop = propertyName.split('.')[0];
1141
+ const subProp = propertyName.replace(prop + '.', '');
1142
+ return this.getCelValue(row[prop], subProp);
1143
+ }
1144
+ }
1145
+ getFormatedValue(gridLayout, value) {
1146
+ if (gridLayout) {
1147
+ switch (gridLayout.formating) {
1148
+ case GridLayoutFormat.date:
1149
+ return this.datePipe.transform(value, gridLayout.customFormat);
1150
+ break;
1151
+ case GridLayoutFormat.number:
1152
+ return this.numberPipe.transform(value, gridLayout.customFormat);
1153
+ case GridLayoutFormat.percent:
1154
+ const valuePrc = value / 100;
1155
+ return this.percentPipe.transform(valuePrc, gridLayout.customFormat);
1156
+ default:
1157
+ return value;
1158
+ break;
1159
+ }
1160
+ }
1161
+ return value;
1162
+ }
1163
+ deleteEnabled(model) {
1164
+ if (this.deleteDisableRule) {
1165
+ return this.evaluateRule(this.deleteDisableRule, model);
1166
+ }
1167
+ else {
1168
+ return true;
1169
+ }
1170
+ }
1171
+ evaluateRule(rules, model) {
1172
+ let result = true;
1173
+ rules.forEach(rule => {
1174
+ let jsonRule;
1175
+ if (typeof rule.rule === 'string') {
1176
+ jsonRule = JSON.parse(rule.rule);
1177
+ }
1178
+ else {
1179
+ jsonRule = rule.rule;
1180
+ }
1181
+ if (rule.parameters) {
1182
+ const data = '{' + rule.parameters.map((item) => {
1183
+ return '"' + item + '":"' + model[item] + '"';
1184
+ }).join(',') + '}';
1185
+ result = jsonLogic.apply(jsonRule, JSON.parse(data));
1186
+ }
1187
+ else {
1188
+ result = jsonLogic.apply(jsonRule);
1189
+ }
1190
+ });
1191
+ return result;
1192
+ }
1193
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: RslIonicGridComponent, deps: [{ token: i1$1.Router }, { token: i1$1.ActivatedRoute }, { token: i2.TranslateService }, { token: i3$1.Location }, { token: i0.Injector }, { token: i4.LoadingController }, { token: i4.NavController }, { token: IonicDialogService }, { token: i3$1.DatePipe }, { token: i3$1.DecimalPipe }, { token: i3$1.PercentPipe }], target: i0.ɵɵFactoryTarget.Component }); }
1194
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.1", type: RslIonicGridComponent, isStandalone: true, selector: "rsl-ionic-grid", inputs: { showSerach: "showSerach", searchFields: "searchFields", customInclude: "customInclude", defaultSort: "defaultSort", defaultSortDirection: "defaultSortDirection", deletePropertyName: "deletePropertyName", defaultFilter: "defaultFilter", showHeader: "showHeader", deleteDisableRule: "deleteDisableRule", model: "model", modelService: "modelService" }, ngImport: i0, template: "<ion-header *ngIf=\"showHeader\">\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-menu-button></ion-menu-button>\n <ion-back-button></ion-back-button>\n </ion-buttons>\n <ng-container [ngTemplateOutlet]=\"header\"></ng-container>\n </ion-toolbar>\n <ng-container [ngTemplateOutlet]=\"search\"></ng-container>\n</ion-header>\n\n<ion-content [fullscreen]=\"true\">\n\n <ion-refresher slot=\"fixed\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <ion-list>\n <ng-container *ngFor=\"let item of data\">\n <ion-item-sliding>\n <ng-container [ngTemplateOutlet]=\"listItem\" [ngTemplateOutletContext]=\"{item}\"></ng-container>\n <ion-item-options *ngIf=\"deleteEnabled(item)\" side=\"end\">\n <ion-item-option color=\"danger\">\n <ion-icon slot=\"icon-only\" name=\"trash\" (click)='deleteModel(item)'></ion-icon>\n </ion-item-option>\n </ion-item-options>\n </ion-item-sliding>\n </ng-container>\n </ion-list>\n <ion-infinite-scroll threshold=\"100px\" (ionInfinite)=\"loadData($event)\">\n <ion-infinite-scroll-content loadingSpinner=\"bubbles\" loadingText=\"Loading more data...\">\n </ion-infinite-scroll-content>\n </ion-infinite-scroll>\n\n</ion-content>\n\n<ng-template #header>\n <ion-title class=\"ion-text-center\">{{title |translate}}</ion-title>\n <ion-button slot=\"end\" (click)=\"onAdd()\" fill=\"clear\">\n <ion-icon size=\"large\" name=\"add\"></ion-icon>\n </ion-button>\n</ng-template>\n\n<ng-template #search>\n <ion-toolbar *ngIf=\"showSerach\">\n <ion-searchbar [debounce]=\"1000\" (ionChange)=\"handleChange($event)\"></ion-searchbar>\n </ion-toolbar>\n</ng-template>\n\n<ng-template #listItem let-item='item'>\n <ion-item button (click)='editModel(item)'>\n <ion-label>\n <ng-container *ngFor=\"let row of gridLayout\">\n <h2 *ngIf=\"row.primary\"> {{getCelValue(item,row.key)}} </h2>\n <h3 *ngIf=\"!row.primary\">{{getCelValue(item,row.key)}} </h3>\n </ng-container>\n </ion-label>\n </ion-item>\n</ng-template>", dependencies: [{ kind: "ngmodule", type: RslIonicModuleModule }, { kind: "directive", type: i3$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i4.IonBackButton, selector: "ion-back-button", inputs: ["color", "defaultHref", "disabled", "icon", "mode", "routerAnimation", "text", "type"] }, { kind: "component", type: i4.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: i4.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i4.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i4.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i4.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i4.IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: i4.IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: i4.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i4.IonItemOption, selector: "ion-item-option", inputs: ["color", "disabled", "download", "expandable", "href", "mode", "rel", "target", "type"] }, { kind: "component", type: i4.IonItemOptions, selector: "ion-item-options", inputs: ["side"] }, { kind: "component", type: i4.IonItemSliding, selector: "ion-item-sliding", inputs: ["disabled"] }, { kind: "component", type: i4.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i4.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i4.IonMenuButton, selector: "ion-menu-button", inputs: ["autoHide", "color", "disabled", "menu", "mode", "type"] }, { kind: "component", type: i4.IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: i4.IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: i4.IonSearchbar, selector: "ion-searchbar", inputs: ["animated", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "mode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value"] }, { kind: "component", type: i4.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i4.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i4.TextValueAccessor, selector: "ion-input:not([type=number]),ion-textarea,ion-searchbar" }, { kind: "directive", type: i4.IonBackButtonDelegate, selector: "ion-back-button", inputs: ["defaultHref", "routerAnimation"] }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] }); }
1195
+ }
1196
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: RslIonicGridComponent, decorators: [{
1197
+ type: Component,
1198
+ args: [{ standalone: true, selector: 'rsl-ionic-grid', imports: [RslIonicModuleModule], template: "<ion-header *ngIf=\"showHeader\">\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-menu-button></ion-menu-button>\n <ion-back-button></ion-back-button>\n </ion-buttons>\n <ng-container [ngTemplateOutlet]=\"header\"></ng-container>\n </ion-toolbar>\n <ng-container [ngTemplateOutlet]=\"search\"></ng-container>\n</ion-header>\n\n<ion-content [fullscreen]=\"true\">\n\n <ion-refresher slot=\"fixed\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <ion-list>\n <ng-container *ngFor=\"let item of data\">\n <ion-item-sliding>\n <ng-container [ngTemplateOutlet]=\"listItem\" [ngTemplateOutletContext]=\"{item}\"></ng-container>\n <ion-item-options *ngIf=\"deleteEnabled(item)\" side=\"end\">\n <ion-item-option color=\"danger\">\n <ion-icon slot=\"icon-only\" name=\"trash\" (click)='deleteModel(item)'></ion-icon>\n </ion-item-option>\n </ion-item-options>\n </ion-item-sliding>\n </ng-container>\n </ion-list>\n <ion-infinite-scroll threshold=\"100px\" (ionInfinite)=\"loadData($event)\">\n <ion-infinite-scroll-content loadingSpinner=\"bubbles\" loadingText=\"Loading more data...\">\n </ion-infinite-scroll-content>\n </ion-infinite-scroll>\n\n</ion-content>\n\n<ng-template #header>\n <ion-title class=\"ion-text-center\">{{title |translate}}</ion-title>\n <ion-button slot=\"end\" (click)=\"onAdd()\" fill=\"clear\">\n <ion-icon size=\"large\" name=\"add\"></ion-icon>\n </ion-button>\n</ng-template>\n\n<ng-template #search>\n <ion-toolbar *ngIf=\"showSerach\">\n <ion-searchbar [debounce]=\"1000\" (ionChange)=\"handleChange($event)\"></ion-searchbar>\n </ion-toolbar>\n</ng-template>\n\n<ng-template #listItem let-item='item'>\n <ion-item button (click)='editModel(item)'>\n <ion-label>\n <ng-container *ngFor=\"let row of gridLayout\">\n <h2 *ngIf=\"row.primary\"> {{getCelValue(item,row.key)}} </h2>\n <h3 *ngIf=\"!row.primary\">{{getCelValue(item,row.key)}} </h3>\n </ng-container>\n </ion-label>\n </ion-item>\n</ng-template>" }]
1199
+ }], ctorParameters: function () { return [{ type: i1$1.Router }, { type: i1$1.ActivatedRoute }, { type: i2.TranslateService }, { type: i3$1.Location }, { type: i0.Injector }, { type: i4.LoadingController }, { type: i4.NavController }, { type: IonicDialogService }, { type: i3$1.DatePipe }, { type: i3$1.DecimalPipe }, { type: i3$1.PercentPipe }]; }, propDecorators: { showSerach: [{
1200
+ type: Input
1201
+ }], searchFields: [{
1202
+ type: Input
1203
+ }], customInclude: [{
1204
+ type: Input
1205
+ }], defaultSort: [{
1206
+ type: Input
1207
+ }], defaultSortDirection: [{
1208
+ type: Input
1209
+ }], deletePropertyName: [{
1210
+ type: Input
1211
+ }], defaultFilter: [{
1212
+ type: Input
1213
+ }], showHeader: [{
1214
+ type: Input
1215
+ }], deleteDisableRule: [{
1216
+ type: Input
1217
+ }], model: [{
1218
+ type: Input
1219
+ }], modelService: [{
1220
+ type: Input
1221
+ }] } });
1222
+
1223
+ function IonicDataTableLayout(config) {
1224
+ return (target, propertyName) => {
1225
+ const annotations = Reflect.getMetadata('IonicDataTableLayout', target) || [];
1226
+ config.prop = propertyName;
1227
+ config.visible = config.visible === undefined ? true : config.visible;
1228
+ annotations.push(config);
1229
+ Reflect.defineMetadata('IonicDataTableLayout', annotations, target);
1230
+ };
1231
+ }
1232
+
1233
+ function IonicListLayout(config) {
1234
+ return (target, propertyName) => {
1235
+ const annotations = Reflect.getMetadata('IonicListLayout', target) || [];
1236
+ config.key = propertyName;
1237
+ annotations.push(config);
1238
+ Reflect.defineMetadata('IonicListLayout', annotations, target);
1239
+ };
1240
+ }
1241
+
1242
+ /*
1243
+ * Public API Surface of ionic
1244
+ */
1245
+
1246
+ /**
1247
+ * Generated bundle index. Do not edit.
1248
+ */
1249
+
1250
+ export { AccordionWrapperComponent, GenericIonicCrudComponent, IonicDataTableLayout, IonicDialogService, IonicListLayout, PanelWrapperComponent, RepeatTypeComponent, RslIonicDataTableComponent, RslIonicGridComponent, TranslateExtension, fieldMatchValidator, registerTranslateExtension };
1251
+ //# sourceMappingURL=rosoftlab-ionic.mjs.map