@winexist/ngp 0.7.1 → 0.7.2
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.
- package/fesm2022/winexist-ngp.mjs +1102 -0
- package/fesm2022/winexist-ngp.mjs.map +1 -0
- package/index.d.ts +396 -0
- package/package.json +16 -2
- package/.storybook/main.ts +0 -22
- package/.storybook/preview.ts +0 -0
- package/.storybook/tsconfig.json +0 -16
- package/doctor-storybook.log +0 -13
- package/eslint.config.mjs +0 -44
- package/jest.config.ts +0 -21
- package/migration-storybook.log +0 -108
- package/ng-package.json +0 -7
- package/project.json +0 -107
- package/src/index.ts +0 -21
- package/src/lib/classes/crud-abstract.class.ts +0 -325
- package/src/lib/components/dataview/table/data-table.component.html +0 -195
- package/src/lib/components/dataview/table/data-table.component.scss +0 -0
- package/src/lib/components/dataview/table/data-table.component.spec.ts +0 -21
- package/src/lib/components/dataview/table/data-table.component.ts +0 -177
- package/src/lib/components/empty/empty.component.css +0 -0
- package/src/lib/components/empty/empty.component.html +0 -18
- package/src/lib/components/empty/empty.component.spec.ts +0 -21
- package/src/lib/components/empty/empty.component.ts +0 -14
- package/src/lib/components/fg-address/fg-address.component.html +0 -142
- package/src/lib/components/fg-address/fg-address.component.scss +0 -0
- package/src/lib/components/fg-address/fg-address.component.spec.ts +0 -21
- package/src/lib/components/fg-address/fg-address.component.ts +0 -302
- package/src/lib/components/file-upload/file-upload.component.css +0 -0
- package/src/lib/components/file-upload/file-upload.component.html +0 -41
- package/src/lib/components/file-upload/file-upload.component.spec.ts +0 -21
- package/src/lib/components/file-upload/file-upload.component.ts +0 -115
- package/src/lib/components/form-field-wrapper/form-field-wrapper.component.html +0 -7
- package/src/lib/components/form-field-wrapper/form-field-wrapper.component.scss +0 -28
- package/src/lib/components/form-field-wrapper/form-field-wrapper.component.spec.ts +0 -21
- package/src/lib/components/form-field-wrapper/form-field-wrapper.component.ts +0 -65
- package/src/lib/components/select/ng-select/basic/basic-ng-select.component.html +0 -18
- package/src/lib/components/select/ng-select/basic/basic-ng-select.component.scss +0 -0
- package/src/lib/components/select/ng-select/basic/basic-ng-select.component.spec.ts +0 -21
- package/src/lib/components/select/ng-select/basic/basic-ng-select.component.ts +0 -88
- package/src/lib/components/select/ng-select/dynamic/dynamic-select.component.html +0 -7
- package/src/lib/components/select/ng-select/dynamic/dynamic-select.component.scss +0 -0
- package/src/lib/components/select/ng-select/dynamic/dynamic-select.component.spec.ts +0 -21
- package/src/lib/components/select/ng-select/dynamic/dynamic-select.component.ts +0 -122
- package/src/lib/components.css +0 -0
- package/src/lib/components.html +0 -1
- package/src/lib/components.spec.ts +0 -21
- package/src/lib/components.stories.ts +0 -24
- package/src/lib/components.ts +0 -9
- package/src/lib/models/address.model.ts +0 -31
- package/src/lib/models/common.model.ts +0 -4
- package/src/lib/models/paginated.model.ts +0 -14
- package/src/lib/models/table-column.model.ts +0 -10
- package/src/lib/services/address/address.service.spec.ts +0 -16
- package/src/lib/services/address/address.service.ts +0 -24
- package/src/lib/types/api-operations.type.ts +0 -22
- package/src/test-setup.ts +0 -6
- package/tsconfig.json +0 -31
- package/tsconfig.lib.json +0 -21
- package/tsconfig.lib.prod.json +0 -9
- package/tsconfig.spec.json +0 -12
|
@@ -0,0 +1,1102 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, Component, output, signal, effect, ViewChild, ContentChild, Input, forwardRef, inject, Injectable, computed, Injector, untracked } from '@angular/core';
|
|
3
|
+
import * as i3 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import * as i1 from 'primeng/fileupload';
|
|
6
|
+
import { FileUploadModule } from 'primeng/fileupload';
|
|
7
|
+
import * as i4 from '@angular/forms';
|
|
8
|
+
import { NgControl, FormsModule, NG_VALUE_ACCESSOR, FormBuilder, ReactiveFormsModule, NG_VALIDATORS } from '@angular/forms';
|
|
9
|
+
import * as i1$1 from 'primeng/message';
|
|
10
|
+
import { MessageModule } from 'primeng/message';
|
|
11
|
+
import * as i1$2 from '@ng-select/ng-select';
|
|
12
|
+
import { NgSelectModule } from '@ng-select/ng-select';
|
|
13
|
+
import * as i3$1 from 'primeng/floatlabel';
|
|
14
|
+
import { FloatLabelModule } from 'primeng/floatlabel';
|
|
15
|
+
import * as i5 from 'primeng/progressspinner';
|
|
16
|
+
import { ProgressSpinnerModule } from 'primeng/progressspinner';
|
|
17
|
+
import { RxwebValidators } from '@rxweb/reactive-form-validators';
|
|
18
|
+
import * as i1$3 from 'primeng/inputtext';
|
|
19
|
+
import { InputTextModule } from 'primeng/inputtext';
|
|
20
|
+
import * as i2 from 'primeng/inputnumber';
|
|
21
|
+
import { InputNumberModule } from 'primeng/inputnumber';
|
|
22
|
+
import { HttpClient } from '@angular/common/http';
|
|
23
|
+
import * as i3$2 from 'primeng/api';
|
|
24
|
+
import { ConfirmationService, MessageService } from 'primeng/api';
|
|
25
|
+
import * as i4$1 from 'primeng/button';
|
|
26
|
+
import { ButtonModule } from 'primeng/button';
|
|
27
|
+
import { ConfirmDialogModule } from 'primeng/confirmdialog';
|
|
28
|
+
import { DialogModule } from 'primeng/dialog';
|
|
29
|
+
import * as i6 from 'primeng/popover';
|
|
30
|
+
import { PopoverModule } from 'primeng/popover';
|
|
31
|
+
import * as i5$1 from 'primeng/skeleton';
|
|
32
|
+
import { SkeletonModule } from 'primeng/skeleton';
|
|
33
|
+
import * as i2$1 from 'primeng/table';
|
|
34
|
+
import { TableModule } from 'primeng/table';
|
|
35
|
+
import { ToastModule } from 'primeng/toast';
|
|
36
|
+
import { ToolbarModule } from 'primeng/toolbar';
|
|
37
|
+
import { TooltipModule } from 'primeng/tooltip';
|
|
38
|
+
import { tap } from 'rxjs/operators';
|
|
39
|
+
import { __decorate } from 'tslib';
|
|
40
|
+
import { shareReplay, catchError, of, finalize } from 'rxjs';
|
|
41
|
+
import { untilDestroyed, UntilDestroy } from '@ngneat/until-destroy';
|
|
42
|
+
|
|
43
|
+
class EmptyComponent {
|
|
44
|
+
title = input('Section is empty.', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
45
|
+
message = input('No data available.', ...(ngDevMode ? [{ debugName: "message" }] : []));
|
|
46
|
+
imgSrc = input(...(ngDevMode ? [undefined, { debugName: "imgSrc" }] : []));
|
|
47
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: EmptyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
48
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: EmptyComponent, isStandalone: true, selector: "ngp-empty", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, imgSrc: { classPropertyName: "imgSrc", publicName: "imgSrc", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"w-full flex justify-center items-center p-5 h-full\">\n <div class=\"flex items-center gap-3\">\n @if (imgSrc()) {\n <img alt=\"Empty\" [src]=\"imgSrc()\" class=\"w-[80px]\" />\n } @else {\n <div class=\"!rounded-md p-5 !bg-slate-100 mb-6\">\n <span class=\"material-icons !text-gray-400 !text-7xl\"> search_off </span>\n </div>\n }\n\n <div class=\"flex flex-col\">\n <span class=\"!text-gray-900 !text-2xl !font-bold\">{{ title() }}</span>\n @if (message()) {\n <span class=\"!text-gray-400 !text-base\">{{ message() }}</span>\n }\n </div>\n </div>\n</div>", styles: [""] });
|
|
49
|
+
}
|
|
50
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: EmptyComponent, decorators: [{
|
|
51
|
+
type: Component,
|
|
52
|
+
args: [{ selector: 'ngp-empty', imports: [], template: "<div class=\"w-full flex justify-center items-center p-5 h-full\">\n <div class=\"flex items-center gap-3\">\n @if (imgSrc()) {\n <img alt=\"Empty\" [src]=\"imgSrc()\" class=\"w-[80px]\" />\n } @else {\n <div class=\"!rounded-md p-5 !bg-slate-100 mb-6\">\n <span class=\"material-icons !text-gray-400 !text-7xl\"> search_off </span>\n </div>\n }\n\n <div class=\"flex flex-col\">\n <span class=\"!text-gray-900 !text-2xl !font-bold\">{{ title() }}</span>\n @if (message()) {\n <span class=\"!text-gray-400 !text-base\">{{ message() }}</span>\n }\n </div>\n </div>\n</div>" }]
|
|
53
|
+
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], imgSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "imgSrc", required: false }] }] } });
|
|
54
|
+
|
|
55
|
+
class FileUploadComponent {
|
|
56
|
+
fileUploader;
|
|
57
|
+
// Signal-based inputs with defaults
|
|
58
|
+
files = input([], ...(ngDevMode ? [{ debugName: "files" }] : []));
|
|
59
|
+
multiple = input(true, ...(ngDevMode ? [{ debugName: "multiple" }] : []));
|
|
60
|
+
accept = input('.pdf,.png,.jpg,.jpeg,.doc,.docx,.csv,.xls,.xlsx', ...(ngDevMode ? [{ debugName: "accept" }] : []));
|
|
61
|
+
maxFileSize = input(2097152, ...(ngDevMode ? [{ debugName: "maxFileSize" }] : [])); // 2MB in bytes
|
|
62
|
+
placeholder = input('Drag and drop new files here to upload.', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
63
|
+
showUploadButton = input(false, ...(ngDevMode ? [{ debugName: "showUploadButton" }] : []));
|
|
64
|
+
cancelLabel = input('Clear', ...(ngDevMode ? [{ debugName: "cancelLabel" }] : []));
|
|
65
|
+
// Signal-based outputs
|
|
66
|
+
filesSelected = output();
|
|
67
|
+
filesCleared = output();
|
|
68
|
+
// Internal state
|
|
69
|
+
uploadedFiles = signal([], ...(ngDevMode ? [{ debugName: "uploadedFiles" }] : []));
|
|
70
|
+
constructor() {
|
|
71
|
+
effect(() => {
|
|
72
|
+
const _files = this.files();
|
|
73
|
+
if (_files.length) {
|
|
74
|
+
this.uploadedFiles.set(_files.map((file) => this.addFileType(file)));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
onFileSelect(event) {
|
|
79
|
+
const validFiles = event.currentFiles.filter((file) => file.size <= this.maxFileSize() && this.isValidFileType(file));
|
|
80
|
+
if (validFiles.length) {
|
|
81
|
+
// Add type to files before adding to uploadedFiles
|
|
82
|
+
const typedFiles = validFiles.map((file) => this.addFileType(file));
|
|
83
|
+
if (this.multiple()) {
|
|
84
|
+
this.uploadedFiles.update((files) => Array.from(new Set([...files, ...typedFiles])));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
this.uploadedFiles.set(typedFiles);
|
|
88
|
+
}
|
|
89
|
+
this.filesSelected.emit(typedFiles);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
onClear() {
|
|
93
|
+
this.uploadedFiles.set([]);
|
|
94
|
+
this.filesCleared.emit();
|
|
95
|
+
}
|
|
96
|
+
removeFile(index) {
|
|
97
|
+
this.uploadedFiles.update((files) => files.filter((_, i) => i !== index));
|
|
98
|
+
this.filesSelected.emit(this.uploadedFiles());
|
|
99
|
+
}
|
|
100
|
+
isValidFileType(file) {
|
|
101
|
+
const acceptedTypes = this.accept().split(',');
|
|
102
|
+
return acceptedTypes.some((type) => file.name.toLowerCase().endsWith(type.trim().toLowerCase()));
|
|
103
|
+
}
|
|
104
|
+
formatFileSize(bytes) {
|
|
105
|
+
if (bytes === 0)
|
|
106
|
+
return '0 Bytes';
|
|
107
|
+
const k = 1024;
|
|
108
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
109
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
110
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
111
|
+
}
|
|
112
|
+
clear() {
|
|
113
|
+
this.uploadedFiles.set([]);
|
|
114
|
+
if (this.fileUploader?.nativeElement?.clear) {
|
|
115
|
+
this.fileUploader.nativeElement.clear();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Function to determine file type based on extension
|
|
119
|
+
getFileTypeByExtension(file) {
|
|
120
|
+
const fileName = file.name.toLowerCase();
|
|
121
|
+
const imageExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.svg', '.webp'];
|
|
122
|
+
const pdfExtension = '.pdf';
|
|
123
|
+
if (imageExtensions.some((ext) => fileName.endsWith(ext))) {
|
|
124
|
+
return 'image';
|
|
125
|
+
}
|
|
126
|
+
else if (fileName.endsWith(pdfExtension)) {
|
|
127
|
+
return 'pdf';
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
return 'other';
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Function to add type property to file
|
|
134
|
+
addFileType(file) {
|
|
135
|
+
const typedFile = file;
|
|
136
|
+
typedFile.fileType = this.getFileTypeByExtension(file);
|
|
137
|
+
return typedFile;
|
|
138
|
+
}
|
|
139
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
140
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FileUploadComponent, isStandalone: true, selector: "ngp-file-upload", inputs: { files: { classPropertyName: "files", publicName: "files", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, showUploadButton: { classPropertyName: "showUploadButton", publicName: "showUploadButton", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filesSelected: "filesSelected", filesCleared: "filesCleared" }, viewQueries: [{ propertyName: "fileUploader", first: true, predicate: ["fileUploader"], descendants: true }], ngImport: i0, template: "<p-fileupload #fileUploader [multiple]=\"multiple()\" [showUploadButton]=\"showUploadButton()\"\n [cancelLabel]=\"cancelLabel()\" [accept]=\"accept()\" auto=\"false\" [maxFileSize]=\"maxFileSize()\" mode=\"advanced\"\n [customUpload]=\"true\" styleClass=\"!bg-gray-50\" (onSelect)=\"onFileSelect($event)\" (onClear)=\"onClear()\">\n <ng-template #content>\n @if (uploadedFiles().length) {\n <ul class=\"space-y-2\">\n @for (file of uploadedFiles(); track $index) {\n <li class=\"flex justify-between gap-4 p-2 bg-gray-100 rounded\">\n <div class=\"flex gap-2\">\n <ng-container [ngTemplateOutlet]=\"iconTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: file.fileType }\"></ng-container>\n <span class=\"text-sm\"> {{ file.name }} - {{ formatFileSize(file.size) }} </span>\n </div>\n <button type=\"button\" (click)=\"removeFile($index)\" class=\"text-red-500 hover:text-red-700 text-sm\">\n <span class=\"material-icons !text-base\"> cancel </span>\n </button>\n </li>\n }\n </ul>\n } @else {\n <div class=\"flex flex-col items-center gap-3\">\n <img src=\"assets/images/file-upload.svg\" alt=\"File Upload\" class=\"w-28 mx-auto\" />\n <span class=\"font-semibold text-center text-gray-400 text-sm\">\n Drag & drop or<br />\n click the \"Choose\" button to add new files\n </span>\n </div>\n }\n </ng-template>\n <ng-template #file></ng-template>\n</p-fileupload>\n\n<ng-template #iconTemplate let-type>\n @if (type === 'image') {\n <span class=\"material-icons\"> image </span>\n } @else if (type === 'pdf') {\n <span class=\"material-icons\"> picture_as_pdf </span>\n } @else {\n <span class=\"material-icons\"> insert_drive_file </span>\n }\n</ng-template>", styles: [""], dependencies: [{ kind: "ngmodule", type: FileUploadModule }, { kind: "component", type: i1.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
141
|
+
}
|
|
142
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileUploadComponent, decorators: [{
|
|
143
|
+
type: Component,
|
|
144
|
+
args: [{ selector: 'ngp-file-upload', imports: [FileUploadModule, CommonModule], template: "<p-fileupload #fileUploader [multiple]=\"multiple()\" [showUploadButton]=\"showUploadButton()\"\n [cancelLabel]=\"cancelLabel()\" [accept]=\"accept()\" auto=\"false\" [maxFileSize]=\"maxFileSize()\" mode=\"advanced\"\n [customUpload]=\"true\" styleClass=\"!bg-gray-50\" (onSelect)=\"onFileSelect($event)\" (onClear)=\"onClear()\">\n <ng-template #content>\n @if (uploadedFiles().length) {\n <ul class=\"space-y-2\">\n @for (file of uploadedFiles(); track $index) {\n <li class=\"flex justify-between gap-4 p-2 bg-gray-100 rounded\">\n <div class=\"flex gap-2\">\n <ng-container [ngTemplateOutlet]=\"iconTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: file.fileType }\"></ng-container>\n <span class=\"text-sm\"> {{ file.name }} - {{ formatFileSize(file.size) }} </span>\n </div>\n <button type=\"button\" (click)=\"removeFile($index)\" class=\"text-red-500 hover:text-red-700 text-sm\">\n <span class=\"material-icons !text-base\"> cancel </span>\n </button>\n </li>\n }\n </ul>\n } @else {\n <div class=\"flex flex-col items-center gap-3\">\n <img src=\"assets/images/file-upload.svg\" alt=\"File Upload\" class=\"w-28 mx-auto\" />\n <span class=\"font-semibold text-center text-gray-400 text-sm\">\n Drag & drop or<br />\n click the \"Choose\" button to add new files\n </span>\n </div>\n }\n </ng-template>\n <ng-template #file></ng-template>\n</p-fileupload>\n\n<ng-template #iconTemplate let-type>\n @if (type === 'image') {\n <span class=\"material-icons\"> image </span>\n } @else if (type === 'pdf') {\n <span class=\"material-icons\"> picture_as_pdf </span>\n } @else {\n <span class=\"material-icons\"> insert_drive_file </span>\n }\n</ng-template>" }]
|
|
145
|
+
}], ctorParameters: () => [], propDecorators: { fileUploader: [{
|
|
146
|
+
type: ViewChild,
|
|
147
|
+
args: ['fileUploader']
|
|
148
|
+
}], files: [{ type: i0.Input, args: [{ isSignal: true, alias: "files", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], showUploadButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showUploadButton", required: false }] }], cancelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelLabel", required: false }] }], filesSelected: [{ type: i0.Output, args: ["filesSelected"] }], filesCleared: [{ type: i0.Output, args: ["filesCleared"] }] } });
|
|
149
|
+
|
|
150
|
+
// form-field-wrapper.component.ts
|
|
151
|
+
class FormFieldWrapperComponent {
|
|
152
|
+
validationMessages = {
|
|
153
|
+
required: 'This field is required',
|
|
154
|
+
email: 'Please enter a valid email',
|
|
155
|
+
minlength: 'Input does not meet minimum length',
|
|
156
|
+
maxlength: 'Input exceeds maximum length',
|
|
157
|
+
pattern: 'Input format is invalid',
|
|
158
|
+
endTimeBeforeStartTime: 'End time must not be before start time',
|
|
159
|
+
breakStartBeforeEarliestStart: 'Break start time cannot be before the earliest start time'
|
|
160
|
+
};
|
|
161
|
+
control;
|
|
162
|
+
subscription;
|
|
163
|
+
ngAfterContentInit() {
|
|
164
|
+
if (this.control) {
|
|
165
|
+
this.subscription = this.control.statusChanges?.subscribe(() => { });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
ngOnDestroy() {
|
|
169
|
+
this.subscription?.unsubscribe();
|
|
170
|
+
}
|
|
171
|
+
shouldShowError() {
|
|
172
|
+
return (!!this.control &&
|
|
173
|
+
this.control.invalid === true &&
|
|
174
|
+
(this.control.dirty === true || this.control.touched === true));
|
|
175
|
+
}
|
|
176
|
+
getErrorMessage() {
|
|
177
|
+
if (!this.control?.errors) {
|
|
178
|
+
return '';
|
|
179
|
+
}
|
|
180
|
+
const firstErrorKey = Object.keys(this.control.errors)[0];
|
|
181
|
+
const error = this.control.errors[firstErrorKey];
|
|
182
|
+
if (this.control.errors['message']) {
|
|
183
|
+
return this.control.errors['message'];
|
|
184
|
+
}
|
|
185
|
+
if (error?.message) {
|
|
186
|
+
return error.message;
|
|
187
|
+
}
|
|
188
|
+
return this.validationMessages[firstErrorKey] || `Invalid input: ${firstErrorKey}`;
|
|
189
|
+
}
|
|
190
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormFieldWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
191
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FormFieldWrapperComponent, isStandalone: true, selector: "ngp-form-field-wrapper", inputs: { validationMessages: "validationMessages" }, queries: [{ propertyName: "control", first: true, predicate: NgControl, descendants: true }], ngImport: i0, template: "<div class=\"form-field-container\">\n <ng-content></ng-content>\n @if (shouldShowError()) {\n <p-message severity=\"error\" variant=\"simple\" size=\"small\" [text]=\"getErrorMessage()\">\n </p-message>\n }\n</div>", styles: [":host{display:block;margin-bottom:1rem}.form-field-container{display:flex;flex-direction:column;gap:4px}:host ::ng-deep .ng-invalid.ng-touched,:host ::ng-deep .ng-invalid.ng-dirty{border-color:#f44336!important;outline-color:#f44336!important}:host ::ng-deep .ng-invalid.ng-touched input,:host ::ng-deep .ng-invalid.ng-dirty input{border-color:#f44336!important;outline-color:#f44336!important}:host ::ng-deep .ng-invalid.ng-touched .ng-select-container,:host ::ng-deep .ng-invalid.ng-dirty .ng-select-container{border-color:#f44336!important;outline-color:#f44336!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i1$1.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] });
|
|
192
|
+
}
|
|
193
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormFieldWrapperComponent, decorators: [{
|
|
194
|
+
type: Component,
|
|
195
|
+
args: [{ selector: 'ngp-form-field-wrapper', standalone: true, imports: [CommonModule, MessageModule], template: "<div class=\"form-field-container\">\n <ng-content></ng-content>\n @if (shouldShowError()) {\n <p-message severity=\"error\" variant=\"simple\" size=\"small\" [text]=\"getErrorMessage()\">\n </p-message>\n }\n</div>", styles: [":host{display:block;margin-bottom:1rem}.form-field-container{display:flex;flex-direction:column;gap:4px}:host ::ng-deep .ng-invalid.ng-touched,:host ::ng-deep .ng-invalid.ng-dirty{border-color:#f44336!important;outline-color:#f44336!important}:host ::ng-deep .ng-invalid.ng-touched input,:host ::ng-deep .ng-invalid.ng-dirty input{border-color:#f44336!important;outline-color:#f44336!important}:host ::ng-deep .ng-invalid.ng-touched .ng-select-container,:host ::ng-deep .ng-invalid.ng-dirty .ng-select-container{border-color:#f44336!important;outline-color:#f44336!important}\n"] }]
|
|
196
|
+
}], propDecorators: { validationMessages: [{
|
|
197
|
+
type: Input
|
|
198
|
+
}], control: [{
|
|
199
|
+
type: ContentChild,
|
|
200
|
+
args: [NgControl]
|
|
201
|
+
}] } });
|
|
202
|
+
|
|
203
|
+
class BasicNgSelectComponent {
|
|
204
|
+
options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
205
|
+
bindLabel = input('', ...(ngDevMode ? [{ debugName: "bindLabel" }] : []));
|
|
206
|
+
bindValue = input('', ...(ngDevMode ? [{ debugName: "bindValue" }] : []));
|
|
207
|
+
placeholder = input('Select an option', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
208
|
+
clearable = input(true, ...(ngDevMode ? [{ debugName: "clearable" }] : []));
|
|
209
|
+
searchable = input(true, ...(ngDevMode ? [{ debugName: "searchable" }] : []));
|
|
210
|
+
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
211
|
+
label = input(null, ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
212
|
+
required = input(true, ...(ngDevMode ? [{ debugName: "required" }] : []));
|
|
213
|
+
// Internal state
|
|
214
|
+
value = null;
|
|
215
|
+
disabled = false;
|
|
216
|
+
// ControlValueAccessor callbacks
|
|
217
|
+
onChange = () => { };
|
|
218
|
+
onTouched = () => { };
|
|
219
|
+
// Handle value changes from ng-select
|
|
220
|
+
onValueChange(value) {
|
|
221
|
+
this.value = value;
|
|
222
|
+
this.onChange(value);
|
|
223
|
+
}
|
|
224
|
+
writeValue(val) {
|
|
225
|
+
this.value = val;
|
|
226
|
+
}
|
|
227
|
+
registerOnChange(fn) {
|
|
228
|
+
this.onChange = fn;
|
|
229
|
+
}
|
|
230
|
+
registerOnTouched(fn) {
|
|
231
|
+
this.onTouched = fn;
|
|
232
|
+
}
|
|
233
|
+
setDisabledState(isDisabled) {
|
|
234
|
+
this.disabled = isDisabled;
|
|
235
|
+
}
|
|
236
|
+
// Compare function for ng-select
|
|
237
|
+
compareWith = (item, selected) => {
|
|
238
|
+
const bindValueKey = this.bindValue();
|
|
239
|
+
// If no bindValue is set, compare entire objects
|
|
240
|
+
if (!bindValueKey) {
|
|
241
|
+
return item === selected;
|
|
242
|
+
}
|
|
243
|
+
// Handle null/undefined cases
|
|
244
|
+
if (!item || !selected) {
|
|
245
|
+
return item === selected;
|
|
246
|
+
}
|
|
247
|
+
// If selected is a primitive (just the id), compare with item's property
|
|
248
|
+
if (typeof selected !== 'object') {
|
|
249
|
+
return item[bindValueKey] === selected;
|
|
250
|
+
}
|
|
251
|
+
// If both are objects, compare the bindValue property
|
|
252
|
+
return item[bindValueKey] === selected[bindValueKey];
|
|
253
|
+
};
|
|
254
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BasicNgSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
255
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: BasicNgSelectComponent, isStandalone: true, selector: "ngp-basic-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, bindLabel: { classPropertyName: "bindLabel", publicName: "bindLabel", isSignal: true, isRequired: false, transformFunction: null }, bindValue: { classPropertyName: "bindValue", publicName: "bindValue", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
256
|
+
{
|
|
257
|
+
provide: NG_VALUE_ACCESSOR,
|
|
258
|
+
useExisting: forwardRef(() => BasicNgSelectComponent),
|
|
259
|
+
multi: true
|
|
260
|
+
}
|
|
261
|
+
], ngImport: i0, template: "<ngp-form-field-wrapper>\n <p-floatlabel variant=\"in\">\n <ng-select [(ngModel)]=\"value\" [bindLabel]=\"bindLabel()\" [bindValue]=\"bindValue()\" [items]=\"options()\"\n [compareWith]=\"compareWith\" [clearable]=\"clearable()\" (change)=\"onValueChange($event)\">\n <ng-template ng-loadingspinner-tmp>\n <ng-container [ngTemplateOutlet]=\"spinner\" />\n </ng-template>\n </ng-select>\n\n @if (label()) {\n <label class=\"block mb-2\" [ngClass]=\"{'required-label': required() }\">{{ label() }}</label>\n }\n </p-floatlabel>\n</ngp-form-field-wrapper>\n\n<ng-template #spinner>\n <p-progress-spinner ariaLabel=\"loading\" styleClass=\"text-gray-400\" />\n</ng-template>", styles: [""], dependencies: [{ kind: "ngmodule", type: NgSelectModule }, { kind: "component", type: i1$2.NgSelectComponent, selector: "ng-select", inputs: ["ariaLabelDropdown", "ariaLabel", "markFirst", "placeholder", "fixedPlaceholder", "notFoundText", "typeToSearchText", "preventToggleOnRightClick", "addTagText", "loadingText", "clearAllText", "dropdownPosition", "appendTo", "outsideClickEvent", "loading", "closeOnSelect", "hideSelected", "selectOnTab", "openOnEnter", "maxSelectedItems", "groupBy", "groupValue", "bufferAmount", "virtualScroll", "selectableGroup", "tabFocusOnClearButton", "selectableGroupAsModel", "searchFn", "trackByFn", "clearOnBackspace", "labelForId", "inputAttrs", "tabIndex", "readonly", "searchWhileComposing", "minTermLength", "editableSearchTerm", "ngClass", "typeahead", "multiple", "addTag", "searchable", "clearable", "deselectOnClick", "clearSearchOnAdd", "compareWith", "keyDownFn", "bindLabel", "bindValue", "appearance", "isOpen", "items"], outputs: ["bindLabelChange", "bindValueChange", "appearanceChange", "isOpenChange", "itemsChange", "blur", "focus", "change", "open", "close", "search", "clear", "add", "remove", "scroll", "scrollToEnd"], exportAs: ["ngSelect"] }, { kind: "directive", type: i1$2.NgLoadingSpinnerTemplateDirective, selector: "[ng-loadingspinner-tmp]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: "component", type: FormFieldWrapperComponent, selector: "ngp-form-field-wrapper", inputs: ["validationMessages"] }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: i3$1.FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i5.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }] });
|
|
262
|
+
}
|
|
263
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BasicNgSelectComponent, decorators: [{
|
|
264
|
+
type: Component,
|
|
265
|
+
args: [{ selector: 'ngp-basic-select', imports: [NgSelectModule, FormsModule, CommonModule, FormFieldWrapperComponent, FloatLabelModule, ProgressSpinnerModule], providers: [
|
|
266
|
+
{
|
|
267
|
+
provide: NG_VALUE_ACCESSOR,
|
|
268
|
+
useExisting: forwardRef(() => BasicNgSelectComponent),
|
|
269
|
+
multi: true
|
|
270
|
+
}
|
|
271
|
+
], template: "<ngp-form-field-wrapper>\n <p-floatlabel variant=\"in\">\n <ng-select [(ngModel)]=\"value\" [bindLabel]=\"bindLabel()\" [bindValue]=\"bindValue()\" [items]=\"options()\"\n [compareWith]=\"compareWith\" [clearable]=\"clearable()\" (change)=\"onValueChange($event)\">\n <ng-template ng-loadingspinner-tmp>\n <ng-container [ngTemplateOutlet]=\"spinner\" />\n </ng-template>\n </ng-select>\n\n @if (label()) {\n <label class=\"block mb-2\" [ngClass]=\"{'required-label': required() }\">{{ label() }}</label>\n }\n </p-floatlabel>\n</ngp-form-field-wrapper>\n\n<ng-template #spinner>\n <p-progress-spinner ariaLabel=\"loading\" styleClass=\"text-gray-400\" />\n</ng-template>" }]
|
|
272
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], bindLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindLabel", required: false }] }], bindValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindValue", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }] } });
|
|
273
|
+
|
|
274
|
+
class AddressService {
|
|
275
|
+
url = `/api/v1/records/address`;
|
|
276
|
+
http = inject(HttpClient);
|
|
277
|
+
getProvinces() {
|
|
278
|
+
return this.http.get(`${this.url}/provinces`);
|
|
279
|
+
}
|
|
280
|
+
getMunicipalities(provinceId) {
|
|
281
|
+
return this.http.get(`${this.url}/municipalities/${provinceId}`);
|
|
282
|
+
}
|
|
283
|
+
getBarangays(muncipalityId, params) {
|
|
284
|
+
return this.http.get(`${this.url}/barangay/${muncipalityId}`, { params });
|
|
285
|
+
}
|
|
286
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AddressService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
287
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AddressService, providedIn: 'root' });
|
|
288
|
+
}
|
|
289
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AddressService, decorators: [{
|
|
290
|
+
type: Injectable,
|
|
291
|
+
args: [{
|
|
292
|
+
providedIn: 'root'
|
|
293
|
+
}]
|
|
294
|
+
}] });
|
|
295
|
+
|
|
296
|
+
class FgAddressComponent {
|
|
297
|
+
showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : []));
|
|
298
|
+
isCreateMode = input(true, ...(ngDevMode ? [{ debugName: "isCreateMode" }] : []));
|
|
299
|
+
isViewMode = input(false, ...(ngDevMode ? [{ debugName: "isViewMode" }] : []));
|
|
300
|
+
addressForm;
|
|
301
|
+
provHttp$;
|
|
302
|
+
cityHttp$;
|
|
303
|
+
barangayHttp$;
|
|
304
|
+
provinceOptions = [];
|
|
305
|
+
cityOptions = [];
|
|
306
|
+
barangayOptions = [];
|
|
307
|
+
isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
|
|
308
|
+
pendingAddress = null;
|
|
309
|
+
isInitializing = false;
|
|
310
|
+
detectedEditMode = false;
|
|
311
|
+
onChange = () => { };
|
|
312
|
+
onTouched = () => { };
|
|
313
|
+
addressService = inject(AddressService);
|
|
314
|
+
fb = inject(FormBuilder);
|
|
315
|
+
constructor() {
|
|
316
|
+
this.addressForm = this.fb.group({
|
|
317
|
+
line1: [null, RxwebValidators.required()],
|
|
318
|
+
line2: [null],
|
|
319
|
+
barangay: [null, RxwebValidators.required()],
|
|
320
|
+
city: [null, RxwebValidators.required()],
|
|
321
|
+
province: [null, RxwebValidators.required()],
|
|
322
|
+
country: ['Philippines', RxwebValidators.required()],
|
|
323
|
+
zipCode: [null, RxwebValidators.required()],
|
|
324
|
+
landmark: [null, RxwebValidators.required()]
|
|
325
|
+
});
|
|
326
|
+
// Use effect to watch for form value changes
|
|
327
|
+
effect(() => {
|
|
328
|
+
if (this.isDisabled()) {
|
|
329
|
+
this.addressForm.disable({ emitEvent: false });
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
this.addressForm.enable({ emitEvent: false });
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
// Subscribe to form changes
|
|
336
|
+
this.addressForm.valueChanges.subscribe((value) => {
|
|
337
|
+
this.onChange(value);
|
|
338
|
+
this.onTouched();
|
|
339
|
+
});
|
|
340
|
+
this.loadProvince();
|
|
341
|
+
// Handle province changes - works for both create and edit mode
|
|
342
|
+
this.addressForm.get('province')?.valueChanges.subscribe((prov) => {
|
|
343
|
+
if (prov && !this.isInitializing) {
|
|
344
|
+
this.clearFieldByName('city');
|
|
345
|
+
this.clearFieldByName('barangay');
|
|
346
|
+
this.cityOptions = [];
|
|
347
|
+
this.barangayOptions = [];
|
|
348
|
+
this.loadCityByProvinceId(prov.id);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
// Handle city changes - works for both create and edit mode
|
|
352
|
+
this.addressForm.get('city')?.valueChanges.subscribe((city) => {
|
|
353
|
+
if (city && !this.isInitializing) {
|
|
354
|
+
this.clearFieldByName('barangay');
|
|
355
|
+
this.barangayOptions = [];
|
|
356
|
+
this.loadBarangayByCityId(city.id);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
clearFieldByName(fieldName) {
|
|
361
|
+
this.addressForm.get(fieldName)?.setValue(null, { emitEvent: false });
|
|
362
|
+
}
|
|
363
|
+
loadProvince() {
|
|
364
|
+
this.provHttp$ = this.addressService.getProvinces().subscribe((res) => {
|
|
365
|
+
this.provinceOptions = res;
|
|
366
|
+
// If we have a pending address to load, process it now
|
|
367
|
+
if (this.pendingAddress) {
|
|
368
|
+
this.initializeEditMode(this.pendingAddress);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
loadCityByProvinceId(id) {
|
|
373
|
+
this.cityHttp$ = this.addressService.getMunicipalities(id).subscribe((res) => {
|
|
374
|
+
this.cityOptions = res;
|
|
375
|
+
// Continue initialization if needed
|
|
376
|
+
if (this.isInitializing && this.pendingAddress) {
|
|
377
|
+
this.setCityFromPending();
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
loadBarangayByCityId(id) {
|
|
382
|
+
this.barangayHttp$ = this.addressService.getBarangays(id).subscribe((res) => {
|
|
383
|
+
this.barangayOptions = res;
|
|
384
|
+
// Continue initialization if needed
|
|
385
|
+
if (this.isInitializing && this.pendingAddress) {
|
|
386
|
+
this.setBarangayFromPending();
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Detects if the address contains data that requires edit mode initialization
|
|
392
|
+
*/
|
|
393
|
+
isEditModeAddress(address) {
|
|
394
|
+
// Check if any cascading field (province, city, barangay) is a string (name)
|
|
395
|
+
// This indicates data from backend that needs to be matched with dropdown options
|
|
396
|
+
return ((typeof address.province === 'string' && address.province !== '') ||
|
|
397
|
+
(typeof address.city === 'string' && address.city !== '') ||
|
|
398
|
+
(typeof address.barangay === 'string' && address.barangay !== ''));
|
|
399
|
+
}
|
|
400
|
+
initializeEditMode(address) {
|
|
401
|
+
this.isInitializing = true;
|
|
402
|
+
// Set non-cascading fields first
|
|
403
|
+
this.addressForm.patchValue({
|
|
404
|
+
line1: address.line1,
|
|
405
|
+
line2: address.line2,
|
|
406
|
+
country: address.country || 'Philippines',
|
|
407
|
+
zipCode: address.zipCode,
|
|
408
|
+
landmark: address.landmark
|
|
409
|
+
}, { emitEvent: false });
|
|
410
|
+
// Find and set province
|
|
411
|
+
if (address.province && typeof address.province === 'string') {
|
|
412
|
+
const provinceItem = this.provinceOptions.find((p) => p.name.toLowerCase() === address.province?.toLowerCase());
|
|
413
|
+
if (provinceItem) {
|
|
414
|
+
this.addressForm.get('province')?.setValue(provinceItem, { emitEvent: false });
|
|
415
|
+
this.loadCityByProvinceId(provinceItem.id);
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
this.completeInitialization();
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
this.completeInitialization();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
setCityFromPending() {
|
|
426
|
+
if (!this.pendingAddress?.city || typeof this.pendingAddress.city !== 'string') {
|
|
427
|
+
this.completeInitialization();
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
const cityItem = this.cityOptions.find((c) => c.name.toLowerCase() === this.pendingAddress.city?.toLowerCase());
|
|
431
|
+
if (cityItem) {
|
|
432
|
+
this.addressForm.get('city')?.setValue(cityItem, { emitEvent: false });
|
|
433
|
+
this.loadBarangayByCityId(cityItem.id);
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
this.completeInitialization();
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
setBarangayFromPending() {
|
|
440
|
+
if (!this.pendingAddress?.barangay || typeof this.pendingAddress.barangay !== 'string') {
|
|
441
|
+
this.completeInitialization();
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const barangayItem = this.barangayOptions.find((b) => b.name.toLowerCase() === this.pendingAddress.barangay?.toLowerCase());
|
|
445
|
+
if (barangayItem) {
|
|
446
|
+
this.addressForm.get('barangay')?.setValue(barangayItem, { emitEvent: false });
|
|
447
|
+
}
|
|
448
|
+
this.completeInitialization();
|
|
449
|
+
}
|
|
450
|
+
completeInitialization() {
|
|
451
|
+
this.isInitializing = false;
|
|
452
|
+
this.pendingAddress = null;
|
|
453
|
+
}
|
|
454
|
+
// ControlValueAccessor methods
|
|
455
|
+
writeValue(value) {
|
|
456
|
+
if (value) {
|
|
457
|
+
// Auto-detect if this is edit mode based on the address data structure
|
|
458
|
+
this.detectedEditMode = this.isEditModeAddress(value);
|
|
459
|
+
if (this.detectedEditMode) {
|
|
460
|
+
// Address contains string values (names) - needs initialization
|
|
461
|
+
this.pendingAddress = value;
|
|
462
|
+
// If provinces are already loaded, start initialization
|
|
463
|
+
if (this.provinceOptions.length > 0) {
|
|
464
|
+
this.initializeEditMode(value);
|
|
465
|
+
}
|
|
466
|
+
// Otherwise, it will be triggered when provinces load
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
// Create mode or already has proper objects
|
|
470
|
+
this.addressForm.patchValue(value, { emitEvent: false });
|
|
471
|
+
// Load cascading data if IDs are present
|
|
472
|
+
const province = value.province;
|
|
473
|
+
if (province && typeof province === 'object' && 'id' in province) {
|
|
474
|
+
this.loadCityByProvinceId(province.id);
|
|
475
|
+
}
|
|
476
|
+
const city = value.city;
|
|
477
|
+
if (city && typeof city === 'object' && 'id' in city) {
|
|
478
|
+
this.loadBarangayByCityId(city.id);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
this.addressForm.reset({ country: 'Philippines' }, { emitEvent: false });
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
registerOnChange(fn) {
|
|
487
|
+
this.onChange = fn;
|
|
488
|
+
}
|
|
489
|
+
registerOnTouched(fn) {
|
|
490
|
+
this.onTouched = fn;
|
|
491
|
+
}
|
|
492
|
+
setDisabledState(isDisabled) {
|
|
493
|
+
this.isDisabled?.set(isDisabled);
|
|
494
|
+
if (isDisabled) {
|
|
495
|
+
this.addressForm.disable();
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
this.addressForm.enable();
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
validate(control) {
|
|
502
|
+
return this.addressForm?.valid ? null : { invalidAddress: true };
|
|
503
|
+
}
|
|
504
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FgAddressComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
505
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FgAddressComponent, isStandalone: true, selector: "ngp-fg-address", inputs: { showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, isCreateMode: { classPropertyName: "isCreateMode", publicName: "isCreateMode", isSignal: true, isRequired: false, transformFunction: null }, isViewMode: { classPropertyName: "isViewMode", publicName: "isViewMode", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
506
|
+
{
|
|
507
|
+
provide: NG_VALUE_ACCESSOR,
|
|
508
|
+
useExisting: forwardRef(() => FgAddressComponent),
|
|
509
|
+
multi: true
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
provide: NG_VALIDATORS,
|
|
513
|
+
useExisting: forwardRef(() => FgAddressComponent),
|
|
514
|
+
multi: true
|
|
515
|
+
}
|
|
516
|
+
], ngImport: i0, template: "@if (showHeader()) {\n\t<h2 class=\"text-xl font-semibold mb-4\">Address</h2>\n}\n\n@if (isViewMode()) {\n\t@let address = addressForm.value;\n\n\t<div class=\"grid gap-3 p-4\">\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"country\">Country:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.country || 'Philippines' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"province\">Province:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.province?.name || address.province || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"city\">City/Municipality:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.city?.name || address.city || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"barangay\">Barangay:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.barangay?.name || address.barangay || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"line1\">Line 1:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.line1 || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"line2\">Line 2:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.line2 || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"zipCode\">Zip Code:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.zipCode || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"landmark\">Nearest Landmark:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.landmark || '' }}</p>\n\t\t</div>\n\t</div>\n} @else {\n\t<form [formGroup]=\"addressForm\">\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<input pInputText trim=\"blur\" id=\"country\" formControlName=\"country\" class=\"w-full\" />\n\t\t\t\t\t\t<label for=\"country\" class=\"block mb-2 required-label\">Country</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"province\"\n\t\t\t\t\t\t\t[items]=\"provinceOptions\"\n\t\t\t\t\t\t\t[loading]=\"provHttp$ && !provHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\t\t\t\t\t\t<label for=\"province\" class=\"block mb-2 required-label\">Province</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"city\"\n\t\t\t\t\t\t\t[items]=\"cityOptions\"\n\t\t\t\t\t\t\t[loading]=\"cityHttp$ && !cityHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\t\t\t\t\t\t<label for=\"city\" class=\"block mb-2 required-label\">City/Municipality</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"barangay\"\n\t\t\t\t\t\t\t[items]=\"barangayOptions\"\n\t\t\t\t\t\t\t[loading]=\"barangayHttp$ && !barangayHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\n\t\t\t\t\t\t<label for=\"barangay\" class=\"block mb-2 required-label\">Barangay</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div>\n\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t<label for=\"line1\" class=\"block mb-2 required-label\">Line 1</label>\n\t\t\t\t\t<input pInputText trim=\"blur\" id=\"line1\" formControlName=\"line1\" class=\"w-full\" />\n\t\t\t\t</p-floatlabel>\n\t\t\t</ngp-form-field-wrapper>\n\t\t</div>\n\n\t\t<div>\n\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t<label for=\"line2\" class=\"block mb-2\">Line 2</label>\n\t\t\t\t\t<input pInputText trim=\"blur\" id=\"line2\" formControlName=\"line2\" class=\"w-full\" />\n\t\t\t\t</p-floatlabel>\n\t\t\t</ngp-form-field-wrapper>\n\t\t</div>\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<p-inputnumber\n\t\t\t\t\t\t\t[inputId]=\"'zipCode'\"\n\t\t\t\t\t\t\tformControlName=\"zipCode\"\n\t\t\t\t\t\t\tstyleClass=\"w-full\"\n\t\t\t\t\t\t\t[useGrouping]=\"false\" />\n\t\t\t\t\t\t<label for=\"zipCode\" class=\"block mb-2 required-label\">Zip Code</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<label for=\"landmark\" class=\"block mb-2 required-label\">Nearest Landmark</label>\n\t\t\t\t\t\t<input pInputText trim=\"blur\" id=\"landmark\" formControlName=\"landmark\" class=\"w-full\" />\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\t</form>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i1$3.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i2.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: i3$1.FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: FormFieldWrapperComponent, selector: "ngp-form-field-wrapper", inputs: ["validationMessages"] }, { kind: "ngmodule", type: NgSelectModule }, { kind: "component", type: i1$2.NgSelectComponent, selector: "ng-select", inputs: ["ariaLabelDropdown", "ariaLabel", "markFirst", "placeholder", "fixedPlaceholder", "notFoundText", "typeToSearchText", "preventToggleOnRightClick", "addTagText", "loadingText", "clearAllText", "dropdownPosition", "appendTo", "outsideClickEvent", "loading", "closeOnSelect", "hideSelected", "selectOnTab", "openOnEnter", "maxSelectedItems", "groupBy", "groupValue", "bufferAmount", "virtualScroll", "selectableGroup", "tabFocusOnClearButton", "selectableGroupAsModel", "searchFn", "trackByFn", "clearOnBackspace", "labelForId", "inputAttrs", "tabIndex", "readonly", "searchWhileComposing", "minTermLength", "editableSearchTerm", "ngClass", "typeahead", "multiple", "addTag", "searchable", "clearable", "deselectOnClick", "clearSearchOnAdd", "compareWith", "keyDownFn", "bindLabel", "bindValue", "appearance", "isOpen", "items"], outputs: ["bindLabelChange", "bindValueChange", "appearanceChange", "isOpenChange", "itemsChange", "blur", "focus", "change", "open", "close", "search", "clear", "add", "remove", "scroll", "scrollToEnd"], exportAs: ["ngSelect"] }] });
|
|
517
|
+
}
|
|
518
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FgAddressComponent, decorators: [{
|
|
519
|
+
type: Component,
|
|
520
|
+
args: [{ selector: 'ngp-fg-address', imports: [
|
|
521
|
+
InputTextModule,
|
|
522
|
+
InputNumberModule,
|
|
523
|
+
FloatLabelModule,
|
|
524
|
+
CommonModule,
|
|
525
|
+
ReactiveFormsModule,
|
|
526
|
+
FormFieldWrapperComponent,
|
|
527
|
+
NgSelectModule
|
|
528
|
+
], providers: [
|
|
529
|
+
{
|
|
530
|
+
provide: NG_VALUE_ACCESSOR,
|
|
531
|
+
useExisting: forwardRef(() => FgAddressComponent),
|
|
532
|
+
multi: true
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
provide: NG_VALIDATORS,
|
|
536
|
+
useExisting: forwardRef(() => FgAddressComponent),
|
|
537
|
+
multi: true
|
|
538
|
+
}
|
|
539
|
+
], template: "@if (showHeader()) {\n\t<h2 class=\"text-xl font-semibold mb-4\">Address</h2>\n}\n\n@if (isViewMode()) {\n\t@let address = addressForm.value;\n\n\t<div class=\"grid gap-3 p-4\">\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"country\">Country:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.country || 'Philippines' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"province\">Province:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.province?.name || address.province || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"city\">City/Municipality:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.city?.name || address.city || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"barangay\">Barangay:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.barangay?.name || address.barangay || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"line1\">Line 1:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.line1 || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"line2\">Line 2:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.line2 || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"zipCode\">Zip Code:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.zipCode || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"landmark\">Nearest Landmark:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.landmark || '' }}</p>\n\t\t</div>\n\t</div>\n} @else {\n\t<form [formGroup]=\"addressForm\">\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<input pInputText trim=\"blur\" id=\"country\" formControlName=\"country\" class=\"w-full\" />\n\t\t\t\t\t\t<label for=\"country\" class=\"block mb-2 required-label\">Country</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"province\"\n\t\t\t\t\t\t\t[items]=\"provinceOptions\"\n\t\t\t\t\t\t\t[loading]=\"provHttp$ && !provHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\t\t\t\t\t\t<label for=\"province\" class=\"block mb-2 required-label\">Province</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"city\"\n\t\t\t\t\t\t\t[items]=\"cityOptions\"\n\t\t\t\t\t\t\t[loading]=\"cityHttp$ && !cityHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\t\t\t\t\t\t<label for=\"city\" class=\"block mb-2 required-label\">City/Municipality</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"barangay\"\n\t\t\t\t\t\t\t[items]=\"barangayOptions\"\n\t\t\t\t\t\t\t[loading]=\"barangayHttp$ && !barangayHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\n\t\t\t\t\t\t<label for=\"barangay\" class=\"block mb-2 required-label\">Barangay</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div>\n\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t<label for=\"line1\" class=\"block mb-2 required-label\">Line 1</label>\n\t\t\t\t\t<input pInputText trim=\"blur\" id=\"line1\" formControlName=\"line1\" class=\"w-full\" />\n\t\t\t\t</p-floatlabel>\n\t\t\t</ngp-form-field-wrapper>\n\t\t</div>\n\n\t\t<div>\n\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t<label for=\"line2\" class=\"block mb-2\">Line 2</label>\n\t\t\t\t\t<input pInputText trim=\"blur\" id=\"line2\" formControlName=\"line2\" class=\"w-full\" />\n\t\t\t\t</p-floatlabel>\n\t\t\t</ngp-form-field-wrapper>\n\t\t</div>\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<p-inputnumber\n\t\t\t\t\t\t\t[inputId]=\"'zipCode'\"\n\t\t\t\t\t\t\tformControlName=\"zipCode\"\n\t\t\t\t\t\t\tstyleClass=\"w-full\"\n\t\t\t\t\t\t\t[useGrouping]=\"false\" />\n\t\t\t\t\t\t<label for=\"zipCode\" class=\"block mb-2 required-label\">Zip Code</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<label for=\"landmark\" class=\"block mb-2 required-label\">Nearest Landmark</label>\n\t\t\t\t\t\t<input pInputText trim=\"blur\" id=\"landmark\" formControlName=\"landmark\" class=\"w-full\" />\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\t</form>\n}\n" }]
|
|
540
|
+
}], ctorParameters: () => [], propDecorators: { showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], isCreateMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCreateMode", required: false }] }], isViewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isViewMode", required: false }] }] } });
|
|
541
|
+
|
|
542
|
+
class DataTableComponent {
|
|
543
|
+
dataSource = input([], ...(ngDevMode ? [{ debugName: "dataSource" }] : []));
|
|
544
|
+
columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
545
|
+
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
546
|
+
pageSize = input(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
|
|
547
|
+
totalElements = input(0, ...(ngDevMode ? [{ debugName: "totalElements" }] : []));
|
|
548
|
+
currentPage = input(0, ...(ngDevMode ? [{ debugName: "currentPage" }] : []));
|
|
549
|
+
showDefaultActions = input(true, ...(ngDevMode ? [{ debugName: "showDefaultActions" }] : []));
|
|
550
|
+
emptyMessage = input('No data available.', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : []));
|
|
551
|
+
hasDeleteAction = input(true, ...(ngDevMode ? [{ debugName: "hasDeleteAction" }] : []));
|
|
552
|
+
hasEditAction = input(true, ...(ngDevMode ? [{ debugName: "hasEditAction" }] : []));
|
|
553
|
+
canEdit = input(() => true, ...(ngDevMode ? [{ debugName: "canEdit" }] : []));
|
|
554
|
+
hasViewAction = input(true, ...(ngDevMode ? [{ debugName: "hasViewAction" }] : []));
|
|
555
|
+
entityName = input('', ...(ngDevMode ? [{ debugName: "entityName" }] : []));
|
|
556
|
+
isPaginated = input(true, ...(ngDevMode ? [{ debugName: "isPaginated" }] : []));
|
|
557
|
+
showCustomAction = input(false, ...(ngDevMode ? [{ debugName: "showCustomAction" }] : []));
|
|
558
|
+
showRowNumbers = input(false, ...(ngDevMode ? [{ debugName: "showRowNumbers" }] : []));
|
|
559
|
+
rowNumberHeader = input('', ...(ngDevMode ? [{ debugName: "rowNumberHeader" }] : []));
|
|
560
|
+
// Internal signals
|
|
561
|
+
data = signal([], ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
562
|
+
filteredData = signal([], ...(ngDevMode ? [{ debugName: "filteredData" }] : []));
|
|
563
|
+
dialogVisible = signal(false, ...(ngDevMode ? [{ debugName: "dialogVisible" }] : []));
|
|
564
|
+
dialogTitle = signal('Add Item', ...(ngDevMode ? [{ debugName: "dialogTitle" }] : []));
|
|
565
|
+
editingItem = signal(null, ...(ngDevMode ? [{ debugName: "editingItem" }] : []));
|
|
566
|
+
// Custom event emitters
|
|
567
|
+
add = output();
|
|
568
|
+
edit = output();
|
|
569
|
+
deleteAction = output();
|
|
570
|
+
view = output();
|
|
571
|
+
pageChange = output();
|
|
572
|
+
sortChange = output();
|
|
573
|
+
actions = computed(() => [this.hasViewAction(), this.hasEditAction(), this.hasDeleteAction()], ...(ngDevMode ? [{ debugName: "actions" }] : []));
|
|
574
|
+
actionsLength = computed(() => this.actions().filter((action) => !!action).length, ...(ngDevMode ? [{ debugName: "actionsLength" }] : []));
|
|
575
|
+
actionItems = computed(() => {
|
|
576
|
+
return [
|
|
577
|
+
{
|
|
578
|
+
label: 'View ' + this.entityName(),
|
|
579
|
+
visible: this.hasViewAction(),
|
|
580
|
+
icon: 'pi-search'
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
label: 'Update ' + this.entityName(),
|
|
584
|
+
visible: this.hasEditAction(),
|
|
585
|
+
icon: 'pi-pen-to-square',
|
|
586
|
+
shouldShow: (item) => this.canEdit()(item)
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
label: 'Delete ' + this.entityName(),
|
|
590
|
+
visible: this.hasDeleteAction(),
|
|
591
|
+
icon: 'pi-trash'
|
|
592
|
+
}
|
|
593
|
+
];
|
|
594
|
+
}, ...(ngDevMode ? [{ debugName: "actionItems" }] : []));
|
|
595
|
+
// Content children for custom templates
|
|
596
|
+
formTemplate;
|
|
597
|
+
table;
|
|
598
|
+
// Services
|
|
599
|
+
http = inject(HttpClient);
|
|
600
|
+
confirmationService = inject(ConfirmationService);
|
|
601
|
+
messageService = inject(MessageService);
|
|
602
|
+
// Column filters for individual column filtering
|
|
603
|
+
filterValues = {};
|
|
604
|
+
// For custom cell templates
|
|
605
|
+
customTemplates = new Map();
|
|
606
|
+
constructor() {
|
|
607
|
+
// Effect to update filtered data when raw data changes
|
|
608
|
+
effect(() => {
|
|
609
|
+
const sourceData = this.dataSource();
|
|
610
|
+
this.data.set([...sourceData]);
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
// Register a custom template for a specific column
|
|
614
|
+
registerTemplate(field, template) {
|
|
615
|
+
this.customTemplates.set(field, template);
|
|
616
|
+
}
|
|
617
|
+
handlePageChange(event) {
|
|
618
|
+
this.pageChange.emit(event);
|
|
619
|
+
}
|
|
620
|
+
handleSort(event) {
|
|
621
|
+
const column = this.columns().find((col) => col.field === event.field);
|
|
622
|
+
const actualSortField = column?.sortField ?? event.field;
|
|
623
|
+
const order = event.order === 1 ? 'ASC' : 'DESC';
|
|
624
|
+
this.sortChange.emit({
|
|
625
|
+
sort: actualSortField,
|
|
626
|
+
order
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
resetTableSort() {
|
|
630
|
+
if (this.table) {
|
|
631
|
+
this.table.sortOrder = 0;
|
|
632
|
+
this.table.sortField = null;
|
|
633
|
+
this.table.tableService.onSort(null);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
// Helper to safely get nested property values using dot notation
|
|
637
|
+
getItemValue(item, field, column) {
|
|
638
|
+
if (column && typeof column.render === 'function') {
|
|
639
|
+
return column.render(item);
|
|
640
|
+
}
|
|
641
|
+
return field
|
|
642
|
+
.split('.')
|
|
643
|
+
.reduce((obj, key) => obj?.[key] ?? null, item);
|
|
644
|
+
}
|
|
645
|
+
perFormActionFromPopover(item, actionType) {
|
|
646
|
+
if (actionType.includes('View')) {
|
|
647
|
+
this.view.emit(item);
|
|
648
|
+
}
|
|
649
|
+
else if (actionType.includes('Update')) {
|
|
650
|
+
this.edit.emit(item);
|
|
651
|
+
}
|
|
652
|
+
else if (actionType.includes('Delete')) {
|
|
653
|
+
this.deleteAction.emit(item);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
657
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DataTableComponent, isStandalone: true, selector: "ngp-data-table", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, totalElements: { classPropertyName: "totalElements", publicName: "totalElements", isSignal: true, isRequired: false, transformFunction: null }, currentPage: { classPropertyName: "currentPage", publicName: "currentPage", isSignal: true, isRequired: false, transformFunction: null }, showDefaultActions: { classPropertyName: "showDefaultActions", publicName: "showDefaultActions", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, hasDeleteAction: { classPropertyName: "hasDeleteAction", publicName: "hasDeleteAction", isSignal: true, isRequired: false, transformFunction: null }, hasEditAction: { classPropertyName: "hasEditAction", publicName: "hasEditAction", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, hasViewAction: { classPropertyName: "hasViewAction", publicName: "hasViewAction", isSignal: true, isRequired: false, transformFunction: null }, entityName: { classPropertyName: "entityName", publicName: "entityName", isSignal: true, isRequired: false, transformFunction: null }, isPaginated: { classPropertyName: "isPaginated", publicName: "isPaginated", isSignal: true, isRequired: false, transformFunction: null }, showCustomAction: { classPropertyName: "showCustomAction", publicName: "showCustomAction", isSignal: true, isRequired: false, transformFunction: null }, showRowNumbers: { classPropertyName: "showRowNumbers", publicName: "showRowNumbers", isSignal: true, isRequired: false, transformFunction: null }, rowNumberHeader: { classPropertyName: "rowNumberHeader", publicName: "rowNumberHeader", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { add: "add", edit: "edit", deleteAction: "deleteAction", view: "view", pageChange: "pageChange", sortChange: "sortChange" }, providers: [ConfirmationService, MessageService], queries: [{ propertyName: "formTemplate", first: true, predicate: ["formTemplate"], descendants: true }], viewQueries: [{ propertyName: "table", first: true, predicate: ["dt"], descendants: true }], ngImport: i0, template: "<div class=\"card\">\n\t<p-table\n\t\t#dt\n\t\t[value]=\"data()\"\n\t\t[paginator]=\"isPaginated()\"\n\t\t[rows]=\"pageSize()\"\n\t\t[rowsPerPageOptions]=\"[5, 10, 25, 50]\"\n\t\t[rowHover]=\"true\"\n\t\t[loading]=\"loading()\"\n\t\t[showLoader]=\"false\"\n\t\t[scrollable]=\"true\"\n\t\tstyleClass=\"p-datatable-sm\"\n\t\t[totalRecords]=\"totalElements()\"\n\t\t[lazy]=\"isPaginated()\"\n\t\t[first]=\"currentPage() * pageSize()\"\n\t\tpaginatorDropdownAppendTo=\"body\"\n\t\t(onPage)=\"handlePageChange($event)\"\n\t\t(onSort)=\"handleSort($event)\">\n\t\t<ng-template pTemplate=\"header\">\n\t\t\t<tr>\n\t\t\t\t@if (showRowNumbers()) {\n\t\t\t\t\t<th class=\"text-left !font-bold !text-gray-500 !w-1\" scope=\"col\">{{\n\t\t\t\t\t\trowNumberHeader()\n\t\t\t\t\t}}</th>\n\t\t\t\t}\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<th\n\t\t\t\t\t\t[pSortableColumn]=\"column.sortable ? column.field : undefined\"\n\t\t\t\t\t\tclass=\"text-left !font-bold !text-gray-500\"\n\t\t\t\t\t\t[ngClass]=\"{ '!text-center': column.align === 'center' }\"\n\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t[style]=\"{ width: column.width || 'auto' }\">\n\t\t\t\t\t\t{{ column.header }}\n\t\t\t\t\t\t@if (column.sortable) {\n\t\t\t\t\t\t\t<p-sortIcon [field]=\"column.field\"></p-sortIcon>\n\t\t\t\t\t\t}\n\t\t\t\t\t</th>\n\t\t\t\t}\n\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<th class=\"!w-32 !text-center !font-bold !text-gray-500\" scope=\"col\">Actions</th>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template pTemplate=\"body\" let-item let-rowIndex=\"rowIndex\">\n\t\t\t<tr>\n\t\t\t\t@if (showRowNumbers()) {\n\t\t\t\t\t<td class=\"!w-1 text-center\">\n\t\t\t\t\t\t{{ rowIndex + 1 }}\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td [ngClass]=\"{ '!text-center': column.align === 'center' }\">\n\t\t\t\t\t\t@if (customTemplates && customTemplates.get(column.field)) {\n\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get(column.field)!\"\n\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: column.field }\">\n\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t{{ getItemValue(item, column.field, column) }}\n\t\t\t\t\t\t}\n\t\t\t\t\t</td>\n\t\t\t\t}\n\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td class=\"\">\n\t\t\t\t\t\t<div class=\"flex justify-center gap-2\">\n\t\t\t\t\t\t\t@if (showDefaultActions() && actionsLength() < 2 && !showCustomAction()) {\n\t\t\t\t\t\t\t\t<!-- Inline buttons for less than 2 standard actions and no custom action -->\n\t\t\t\t\t\t\t\t@if (hasViewAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-primary\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'View'\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"view.emit(item)\"></button>\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t@if (hasEditAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-primary\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"edit.emit(item)\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'Update'\"></button>\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t@if (hasDeleteAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-danger\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"deleteAction.emit(item)\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'Delete'\"></button>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} @else if (!showDefaultActions() && showCustomAction()) {\n\t\t\t\t\t\t\t\t<!-- Only custom action, no popover needed -->\n\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get('customAction')!\"\n\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: 'customAction' }\">\n\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<!-- Popover menu for 2+ standard actions or when combining with custom action -->\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\ticon=\"pi pi-ellipsis-h\"\n\t\t\t\t\t\t\t\t\tclass=\"p-button-outlined p-button-secondary\"\n\t\t\t\t\t\t\t\t\t(click)=\"po.toggle($event)\"></button>\n\t\t\t\t\t\t\t\t<p-popover #po styleClass=\"!min-w-40\">\n\t\t\t\t\t\t\t\t\t<span class=\"!font-semibold !text-gray-500 block mb-2\">Actions</span>\n\t\t\t\t\t\t\t\t\t<ul class=\"list-none p-0 m-0 flex flex-col\">\n\t\t\t\t\t\t\t\t\t\t@if (showDefaultActions()) {\n\t\t\t\t\t\t\t\t\t\t\t@for (actionItem of actionItems(); track $index) {\n\t\t\t\t\t\t\t\t\t\t\t\t@if (\n\t\t\t\t\t\t\t\t\t\t\t\t\tactionItem.visible &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t(!actionItem.shouldShow || actionItem.shouldShow(item))\n\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tclass=\"flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(click)=\"perFormActionFromPopover(item, actionItem.label)\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"pi\" [ngClass]=\"actionItem.icon\"></span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"font-medium\">{{ actionItem.label }}</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t<!-- Custom action template in popover -->\n\t\t\t\t\t\t\t\t\t\t@if (showCustomAction() && customTemplates.get('customAction')) {\n\t\t\t\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get('customAction')!\"\n\t\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: 'customAction' }\">\n\t\t\t\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t\t</p-popover>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template #loadingbody>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template pTemplate=\"emptymessage\">\n\t\t\t<tr>\n\t\t\t\t<td [attr.colspan]=\"columns().length + 1\" class=\"text-center p-4\">{{ emptyMessage() }}</td>\n\t\t\t</tr>\n\t\t</ng-template>\n\t</p-table>\n</div>\n", styles: [""], 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: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i2$1.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i3$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i2$1.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i2$1.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i4$1.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: ConfirmDialogModule }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: ToastModule }, { kind: "ngmodule", type: ToolbarModule }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i5$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i6.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }] });
|
|
658
|
+
}
|
|
659
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DataTableComponent, decorators: [{
|
|
660
|
+
type: Component,
|
|
661
|
+
args: [{ selector: 'ngp-data-table', imports: [
|
|
662
|
+
CommonModule,
|
|
663
|
+
FormsModule,
|
|
664
|
+
ReactiveFormsModule,
|
|
665
|
+
TableModule,
|
|
666
|
+
ButtonModule,
|
|
667
|
+
InputTextModule,
|
|
668
|
+
ConfirmDialogModule,
|
|
669
|
+
DialogModule,
|
|
670
|
+
TooltipModule,
|
|
671
|
+
ToastModule,
|
|
672
|
+
ToolbarModule,
|
|
673
|
+
SkeletonModule,
|
|
674
|
+
PopoverModule
|
|
675
|
+
], providers: [ConfirmationService, MessageService], template: "<div class=\"card\">\n\t<p-table\n\t\t#dt\n\t\t[value]=\"data()\"\n\t\t[paginator]=\"isPaginated()\"\n\t\t[rows]=\"pageSize()\"\n\t\t[rowsPerPageOptions]=\"[5, 10, 25, 50]\"\n\t\t[rowHover]=\"true\"\n\t\t[loading]=\"loading()\"\n\t\t[showLoader]=\"false\"\n\t\t[scrollable]=\"true\"\n\t\tstyleClass=\"p-datatable-sm\"\n\t\t[totalRecords]=\"totalElements()\"\n\t\t[lazy]=\"isPaginated()\"\n\t\t[first]=\"currentPage() * pageSize()\"\n\t\tpaginatorDropdownAppendTo=\"body\"\n\t\t(onPage)=\"handlePageChange($event)\"\n\t\t(onSort)=\"handleSort($event)\">\n\t\t<ng-template pTemplate=\"header\">\n\t\t\t<tr>\n\t\t\t\t@if (showRowNumbers()) {\n\t\t\t\t\t<th class=\"text-left !font-bold !text-gray-500 !w-1\" scope=\"col\">{{\n\t\t\t\t\t\trowNumberHeader()\n\t\t\t\t\t}}</th>\n\t\t\t\t}\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<th\n\t\t\t\t\t\t[pSortableColumn]=\"column.sortable ? column.field : undefined\"\n\t\t\t\t\t\tclass=\"text-left !font-bold !text-gray-500\"\n\t\t\t\t\t\t[ngClass]=\"{ '!text-center': column.align === 'center' }\"\n\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t[style]=\"{ width: column.width || 'auto' }\">\n\t\t\t\t\t\t{{ column.header }}\n\t\t\t\t\t\t@if (column.sortable) {\n\t\t\t\t\t\t\t<p-sortIcon [field]=\"column.field\"></p-sortIcon>\n\t\t\t\t\t\t}\n\t\t\t\t\t</th>\n\t\t\t\t}\n\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<th class=\"!w-32 !text-center !font-bold !text-gray-500\" scope=\"col\">Actions</th>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template pTemplate=\"body\" let-item let-rowIndex=\"rowIndex\">\n\t\t\t<tr>\n\t\t\t\t@if (showRowNumbers()) {\n\t\t\t\t\t<td class=\"!w-1 text-center\">\n\t\t\t\t\t\t{{ rowIndex + 1 }}\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td [ngClass]=\"{ '!text-center': column.align === 'center' }\">\n\t\t\t\t\t\t@if (customTemplates && customTemplates.get(column.field)) {\n\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get(column.field)!\"\n\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: column.field }\">\n\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t{{ getItemValue(item, column.field, column) }}\n\t\t\t\t\t\t}\n\t\t\t\t\t</td>\n\t\t\t\t}\n\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td class=\"\">\n\t\t\t\t\t\t<div class=\"flex justify-center gap-2\">\n\t\t\t\t\t\t\t@if (showDefaultActions() && actionsLength() < 2 && !showCustomAction()) {\n\t\t\t\t\t\t\t\t<!-- Inline buttons for less than 2 standard actions and no custom action -->\n\t\t\t\t\t\t\t\t@if (hasViewAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-primary\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'View'\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"view.emit(item)\"></button>\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t@if (hasEditAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-primary\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"edit.emit(item)\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'Update'\"></button>\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t@if (hasDeleteAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-danger\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"deleteAction.emit(item)\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'Delete'\"></button>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} @else if (!showDefaultActions() && showCustomAction()) {\n\t\t\t\t\t\t\t\t<!-- Only custom action, no popover needed -->\n\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get('customAction')!\"\n\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: 'customAction' }\">\n\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<!-- Popover menu for 2+ standard actions or when combining with custom action -->\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\ticon=\"pi pi-ellipsis-h\"\n\t\t\t\t\t\t\t\t\tclass=\"p-button-outlined p-button-secondary\"\n\t\t\t\t\t\t\t\t\t(click)=\"po.toggle($event)\"></button>\n\t\t\t\t\t\t\t\t<p-popover #po styleClass=\"!min-w-40\">\n\t\t\t\t\t\t\t\t\t<span class=\"!font-semibold !text-gray-500 block mb-2\">Actions</span>\n\t\t\t\t\t\t\t\t\t<ul class=\"list-none p-0 m-0 flex flex-col\">\n\t\t\t\t\t\t\t\t\t\t@if (showDefaultActions()) {\n\t\t\t\t\t\t\t\t\t\t\t@for (actionItem of actionItems(); track $index) {\n\t\t\t\t\t\t\t\t\t\t\t\t@if (\n\t\t\t\t\t\t\t\t\t\t\t\t\tactionItem.visible &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t(!actionItem.shouldShow || actionItem.shouldShow(item))\n\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tclass=\"flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(click)=\"perFormActionFromPopover(item, actionItem.label)\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"pi\" [ngClass]=\"actionItem.icon\"></span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"font-medium\">{{ actionItem.label }}</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t<!-- Custom action template in popover -->\n\t\t\t\t\t\t\t\t\t\t@if (showCustomAction() && customTemplates.get('customAction')) {\n\t\t\t\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get('customAction')!\"\n\t\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: 'customAction' }\">\n\t\t\t\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t\t</p-popover>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template #loadingbody>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template pTemplate=\"emptymessage\">\n\t\t\t<tr>\n\t\t\t\t<td [attr.colspan]=\"columns().length + 1\" class=\"text-center p-4\">{{ emptyMessage() }}</td>\n\t\t\t</tr>\n\t\t</ng-template>\n\t</p-table>\n</div>\n" }]
|
|
676
|
+
}], ctorParameters: () => [], propDecorators: { dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], totalElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalElements", required: false }] }], currentPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentPage", required: false }] }], showDefaultActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDefaultActions", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], hasDeleteAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasDeleteAction", required: false }] }], hasEditAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasEditAction", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], hasViewAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasViewAction", required: false }] }], entityName: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityName", required: false }] }], isPaginated: [{ type: i0.Input, args: [{ isSignal: true, alias: "isPaginated", required: false }] }], showCustomAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCustomAction", required: false }] }], showRowNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRowNumbers", required: false }] }], rowNumberHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowNumberHeader", required: false }] }], add: [{ type: i0.Output, args: ["add"] }], edit: [{ type: i0.Output, args: ["edit"] }], deleteAction: [{ type: i0.Output, args: ["deleteAction"] }], view: [{ type: i0.Output, args: ["view"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], formTemplate: [{
|
|
677
|
+
type: ContentChild,
|
|
678
|
+
args: ['formTemplate']
|
|
679
|
+
}], table: [{
|
|
680
|
+
type: ViewChild,
|
|
681
|
+
args: ['dt']
|
|
682
|
+
}] } });
|
|
683
|
+
|
|
684
|
+
class DynamicNgSelectComponent {
|
|
685
|
+
apiUrl;
|
|
686
|
+
formatOptions;
|
|
687
|
+
bindLabel = 'description';
|
|
688
|
+
bindValue = 'id';
|
|
689
|
+
placeholder = 'Select';
|
|
690
|
+
isRequired = false;
|
|
691
|
+
options = [];
|
|
692
|
+
value;
|
|
693
|
+
disabled = false;
|
|
694
|
+
tableParams = signal({ page: 0, size: 10 }, ...(ngDevMode ? [{ debugName: "tableParams" }] : []));
|
|
695
|
+
onChange = (_) => { }; // eslint-disable-line
|
|
696
|
+
onTouched = () => { }; // eslint-disable-line
|
|
697
|
+
ngOnInit() {
|
|
698
|
+
this.loadOptions();
|
|
699
|
+
}
|
|
700
|
+
loadOptions() {
|
|
701
|
+
if (!this.apiUrl) {
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
this.getOptions();
|
|
705
|
+
}
|
|
706
|
+
getOptions() {
|
|
707
|
+
this.apiUrl(this.tableParams())
|
|
708
|
+
.pipe(tap((items) => {
|
|
709
|
+
const values = this.formatOptions ? this.formatOptions(items.results) : items.results;
|
|
710
|
+
this.options = [...this.options, ...values];
|
|
711
|
+
if (items.hasNextPage) {
|
|
712
|
+
this.tableParams.update((param) => ({ ...param, page: param.page + 1 }));
|
|
713
|
+
this.getOptions();
|
|
714
|
+
}
|
|
715
|
+
}))
|
|
716
|
+
.subscribe();
|
|
717
|
+
}
|
|
718
|
+
writeValue(value) {
|
|
719
|
+
this.value = value;
|
|
720
|
+
}
|
|
721
|
+
registerOnChange(fn) {
|
|
722
|
+
this.onChange = fn;
|
|
723
|
+
}
|
|
724
|
+
registerOnTouched(fn) {
|
|
725
|
+
this.onTouched = fn;
|
|
726
|
+
}
|
|
727
|
+
setDisabledState(isDisabled) {
|
|
728
|
+
this.disabled = isDisabled;
|
|
729
|
+
}
|
|
730
|
+
onValueChange(value) {
|
|
731
|
+
if (!value) {
|
|
732
|
+
this.value = null;
|
|
733
|
+
this.onChange(null);
|
|
734
|
+
}
|
|
735
|
+
else {
|
|
736
|
+
this.value = value[this.bindValue];
|
|
737
|
+
this.onChange(value[this.bindValue]);
|
|
738
|
+
}
|
|
739
|
+
this.onTouched();
|
|
740
|
+
}
|
|
741
|
+
validate(control) {
|
|
742
|
+
if (this.isRequired &&
|
|
743
|
+
(this.value === null || this.value === undefined || this.value === '')) {
|
|
744
|
+
return { required: true };
|
|
745
|
+
}
|
|
746
|
+
return null;
|
|
747
|
+
}
|
|
748
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicNgSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
749
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DynamicNgSelectComponent, isStandalone: true, selector: "ngp-dynamic-select", inputs: { apiUrl: "apiUrl", formatOptions: "formatOptions", bindLabel: "bindLabel", bindValue: "bindValue", placeholder: "placeholder", isRequired: "isRequired", options: "options" }, providers: [
|
|
750
|
+
{
|
|
751
|
+
provide: NG_VALUE_ACCESSOR,
|
|
752
|
+
useExisting: forwardRef(() => DynamicNgSelectComponent),
|
|
753
|
+
multi: true
|
|
754
|
+
},
|
|
755
|
+
{
|
|
756
|
+
provide: NG_VALIDATORS,
|
|
757
|
+
useExisting: forwardRef(() => DynamicNgSelectComponent),
|
|
758
|
+
multi: true
|
|
759
|
+
}
|
|
760
|
+
], ngImport: i0, template: "<p-floatlabel variant=\"in\">\n <ng-select [items]=\"options\" [bindLabel]=\"bindLabel\" [bindValue]=\"bindValue\" [disabled]=\"disabled\"\n [(ngModel)]=\"value\" [clearable]=\"true\" (change)=\"onValueChange($event)\">\n </ng-select>\n\n <label [class.required-label]=\"isRequired\">{{ placeholder }}</label>\n</p-floatlabel>", dependencies: [{ kind: "ngmodule", type: NgSelectModule }, { kind: "component", type: i1$2.NgSelectComponent, selector: "ng-select", inputs: ["ariaLabelDropdown", "ariaLabel", "markFirst", "placeholder", "fixedPlaceholder", "notFoundText", "typeToSearchText", "preventToggleOnRightClick", "addTagText", "loadingText", "clearAllText", "dropdownPosition", "appendTo", "outsideClickEvent", "loading", "closeOnSelect", "hideSelected", "selectOnTab", "openOnEnter", "maxSelectedItems", "groupBy", "groupValue", "bufferAmount", "virtualScroll", "selectableGroup", "tabFocusOnClearButton", "selectableGroupAsModel", "searchFn", "trackByFn", "clearOnBackspace", "labelForId", "inputAttrs", "tabIndex", "readonly", "searchWhileComposing", "minTermLength", "editableSearchTerm", "ngClass", "typeahead", "multiple", "addTag", "searchable", "clearable", "deselectOnClick", "clearSearchOnAdd", "compareWith", "keyDownFn", "bindLabel", "bindValue", "appearance", "isOpen", "items"], outputs: ["bindLabelChange", "bindValueChange", "appearanceChange", "isOpenChange", "itemsChange", "blur", "focus", "change", "open", "close", "search", "clear", "add", "remove", "scroll", "scrollToEnd"], exportAs: ["ngSelect"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: i3$1.FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }] });
|
|
761
|
+
}
|
|
762
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicNgSelectComponent, decorators: [{
|
|
763
|
+
type: Component,
|
|
764
|
+
args: [{ selector: 'ngp-dynamic-select', imports: [NgSelectModule, FormsModule, CommonModule, FloatLabelModule], providers: [
|
|
765
|
+
{
|
|
766
|
+
provide: NG_VALUE_ACCESSOR,
|
|
767
|
+
useExisting: forwardRef(() => DynamicNgSelectComponent),
|
|
768
|
+
multi: true
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
provide: NG_VALIDATORS,
|
|
772
|
+
useExisting: forwardRef(() => DynamicNgSelectComponent),
|
|
773
|
+
multi: true
|
|
774
|
+
}
|
|
775
|
+
], template: "<p-floatlabel variant=\"in\">\n <ng-select [items]=\"options\" [bindLabel]=\"bindLabel\" [bindValue]=\"bindValue\" [disabled]=\"disabled\"\n [(ngModel)]=\"value\" [clearable]=\"true\" (change)=\"onValueChange($event)\">\n </ng-select>\n\n <label [class.required-label]=\"isRequired\">{{ placeholder }}</label>\n</p-floatlabel>" }]
|
|
776
|
+
}], propDecorators: { apiUrl: [{
|
|
777
|
+
type: Input
|
|
778
|
+
}], formatOptions: [{
|
|
779
|
+
type: Input
|
|
780
|
+
}], bindLabel: [{
|
|
781
|
+
type: Input
|
|
782
|
+
}], bindValue: [{
|
|
783
|
+
type: Input
|
|
784
|
+
}], placeholder: [{
|
|
785
|
+
type: Input
|
|
786
|
+
}], isRequired: [{
|
|
787
|
+
type: Input
|
|
788
|
+
}], options: [{
|
|
789
|
+
type: Input
|
|
790
|
+
}] } });
|
|
791
|
+
|
|
792
|
+
class PaginatedRequest {
|
|
793
|
+
page;
|
|
794
|
+
size;
|
|
795
|
+
sort;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
let CrudAbstractComponent = class CrudAbstractComponent {
|
|
799
|
+
// State signals
|
|
800
|
+
sourceSignal = signal(null, ...(ngDevMode ? [{ debugName: "sourceSignal" }] : []));
|
|
801
|
+
loadingSignal = signal(false, ...(ngDevMode ? [{ debugName: "loadingSignal" }] : []));
|
|
802
|
+
errorSignal = signal(null, ...(ngDevMode ? [{ debugName: "errorSignal" }] : []));
|
|
803
|
+
actionSignal = signal(null, ...(ngDevMode ? [{ debugName: "actionSignal" }] : []));
|
|
804
|
+
firstLoadSignal = signal(true, ...(ngDevMode ? [{ debugName: "firstLoadSignal" }] : []));
|
|
805
|
+
showFormSignal = signal(false, ...(ngDevMode ? [{ debugName: "showFormSignal" }] : []));
|
|
806
|
+
formActionSignal = signal(null, ...(ngDevMode ? [{ debugName: "formActionSignal" }] : []));
|
|
807
|
+
dataSignal = signal(null, ...(ngDevMode ? [{ debugName: "dataSignal" }] : []));
|
|
808
|
+
filters = signal(null, ...(ngDevMode ? [{ debugName: "filters" }] : []));
|
|
809
|
+
tableParams = signal({ page: 0, size: 10 }, ...(ngDevMode ? [{ debugName: "tableParams" }] : []));
|
|
810
|
+
requestParams = computed(() => ({
|
|
811
|
+
...this.filters(),
|
|
812
|
+
...this.tableParams()
|
|
813
|
+
}), ...(ngDevMode ? [{ debugName: "requestParams" }] : []));
|
|
814
|
+
// Injections
|
|
815
|
+
injector = inject(Injector);
|
|
816
|
+
// Public interface
|
|
817
|
+
data = this.dataSignal.asReadonly();
|
|
818
|
+
isLoading = this.loadingSignal.asReadonly();
|
|
819
|
+
error = this.errorSignal.asReadonly();
|
|
820
|
+
currentAction = this.actionSignal.asReadonly();
|
|
821
|
+
isFirstLoad = this.firstLoadSignal.asReadonly();
|
|
822
|
+
isFormVisible = this.showFormSignal.asReadonly();
|
|
823
|
+
formAction = this.formActionSignal.asReadonly();
|
|
824
|
+
safeDataSource = computed(() => {
|
|
825
|
+
const rawData = this.dataSignal();
|
|
826
|
+
const isLoading = this.loadingSignal();
|
|
827
|
+
// Default empty response
|
|
828
|
+
const defaultResponse = {
|
|
829
|
+
hasNextPage: false,
|
|
830
|
+
totalElements: 0,
|
|
831
|
+
results: [],
|
|
832
|
+
currentPage: 0,
|
|
833
|
+
pageSize: 10
|
|
834
|
+
};
|
|
835
|
+
if (!rawData || isLoading)
|
|
836
|
+
return defaultResponse;
|
|
837
|
+
const isPaginatedResponse = (obj) => {
|
|
838
|
+
return (obj !== null &&
|
|
839
|
+
typeof obj === 'object' &&
|
|
840
|
+
'results' in obj &&
|
|
841
|
+
Array.isArray(obj.results) &&
|
|
842
|
+
'totalElements' in obj &&
|
|
843
|
+
typeof obj.totalElements === 'number');
|
|
844
|
+
};
|
|
845
|
+
// Handler for Paginated Response
|
|
846
|
+
if (typeof rawData === 'object' && isPaginatedResponse(rawData)) {
|
|
847
|
+
return {
|
|
848
|
+
results: [...rawData.results],
|
|
849
|
+
totalElements: rawData.totalElements,
|
|
850
|
+
currentPage: rawData.currentPage,
|
|
851
|
+
pageSize: rawData.pageSize,
|
|
852
|
+
hasNextPage: rawData.hasNextPage
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
// Handle array case
|
|
856
|
+
if (Array.isArray(rawData)) {
|
|
857
|
+
return {
|
|
858
|
+
...defaultResponse,
|
|
859
|
+
totalElements: rawData.length,
|
|
860
|
+
results: [...rawData],
|
|
861
|
+
pageSize: rawData.length // For arrays, we typically return all elements
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
// Handle single object case
|
|
865
|
+
return {
|
|
866
|
+
...defaultResponse,
|
|
867
|
+
totalElements: 1,
|
|
868
|
+
results: [rawData],
|
|
869
|
+
pageSize: 1
|
|
870
|
+
};
|
|
871
|
+
}, ...(ngDevMode ? [{ debugName: "safeDataSource" }] : []));
|
|
872
|
+
/**
|
|
873
|
+
* Provides direct access to raw list data without pagination wrapper
|
|
874
|
+
* Returns an empty array if data is not available or not an array
|
|
875
|
+
*/
|
|
876
|
+
rawList = computed(() => {
|
|
877
|
+
const rawData = this.data();
|
|
878
|
+
if (!rawData || this.isLoading()) {
|
|
879
|
+
return [];
|
|
880
|
+
}
|
|
881
|
+
// If it's already an array, return it
|
|
882
|
+
if (Array.isArray(rawData)) {
|
|
883
|
+
return [...rawData];
|
|
884
|
+
}
|
|
885
|
+
// If it's a paginated response with a results property that's an array
|
|
886
|
+
if (typeof rawData === 'object' && 'results' in rawData && Array.isArray(rawData.results)) {
|
|
887
|
+
return [...rawData.results];
|
|
888
|
+
}
|
|
889
|
+
// If it's a single object, return it as an array with one item
|
|
890
|
+
if (typeof rawData === 'object' && !('results' in rawData)) {
|
|
891
|
+
return [rawData];
|
|
892
|
+
}
|
|
893
|
+
// Default fallback
|
|
894
|
+
return [];
|
|
895
|
+
}, ...(ngDevMode ? [{ debugName: "rawList" }] : []));
|
|
896
|
+
// Usage in your component:
|
|
897
|
+
// const items = this.rawList();
|
|
898
|
+
// Current operations state
|
|
899
|
+
currentOperations;
|
|
900
|
+
currentParams;
|
|
901
|
+
// Effect to handle Observable subscriptions
|
|
902
|
+
dataEffect = effect(() => {
|
|
903
|
+
const obs = this.sourceSignal();
|
|
904
|
+
if (!obs) {
|
|
905
|
+
untracked(() => this.dataSignal.set(null));
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
untracked(() => {
|
|
909
|
+
this.loadingSignal.set(true);
|
|
910
|
+
this.errorSignal.set(null);
|
|
911
|
+
const sub = obs
|
|
912
|
+
.pipe(shareReplay(1), catchError((err) => {
|
|
913
|
+
this.errorSignal.set(err);
|
|
914
|
+
return of(null);
|
|
915
|
+
}), finalize(() => this.loadingSignal.set(false)))
|
|
916
|
+
.subscribe((value) => {
|
|
917
|
+
this.dataSignal.set(value);
|
|
918
|
+
});
|
|
919
|
+
return () => sub.unsubscribe();
|
|
920
|
+
});
|
|
921
|
+
}, ...(ngDevMode ? [{ debugName: "dataEffect", injector: this.injector }] : [{ injector: this.injector }]));
|
|
922
|
+
/**
|
|
923
|
+
* Initialize with dynamic service operations
|
|
924
|
+
*/
|
|
925
|
+
initService(operations) {
|
|
926
|
+
this.currentOperations = operations;
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* GET data
|
|
930
|
+
*/
|
|
931
|
+
loadData(params) {
|
|
932
|
+
if (!this.currentOperations?.get)
|
|
933
|
+
return;
|
|
934
|
+
this.executeOperation('get', () => this.currentOperations.get(params), params);
|
|
935
|
+
this.firstLoadSignal.set(false);
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* GET data by ID
|
|
939
|
+
*/
|
|
940
|
+
getById(id, params) {
|
|
941
|
+
if (!this.currentOperations?.getById)
|
|
942
|
+
return of(null);
|
|
943
|
+
return this.executeOperation('get', () => this.currentOperations.getById(id, params));
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* CREATE data
|
|
947
|
+
*/
|
|
948
|
+
createData(data) {
|
|
949
|
+
if (!this.currentOperations?.create)
|
|
950
|
+
return of(null);
|
|
951
|
+
return this.executeOperation('create', () => this.currentOperations.create(data));
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* UPDATE data
|
|
955
|
+
*/
|
|
956
|
+
updateData(data) {
|
|
957
|
+
if (!this.currentOperations?.update)
|
|
958
|
+
return of(null);
|
|
959
|
+
return this.executeOperation('update', () => this.currentOperations.update(data));
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* UPDATE data by ID
|
|
963
|
+
*/
|
|
964
|
+
updateById(id, data) {
|
|
965
|
+
if (!this.currentOperations?.updateById)
|
|
966
|
+
return of(null);
|
|
967
|
+
return this.executeOperation('updateById', () => this.currentOperations.updateById(id, data));
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* DELETE data
|
|
971
|
+
*/
|
|
972
|
+
deleteData(id) {
|
|
973
|
+
if (!this.currentOperations?.delete)
|
|
974
|
+
return of(null);
|
|
975
|
+
return this.executeOperation('delete', () => this.currentOperations.delete(id));
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* UPDATE status
|
|
979
|
+
*/
|
|
980
|
+
updateStatus(id, status) {
|
|
981
|
+
if (!this.currentOperations?.updateStatus)
|
|
982
|
+
return of(null);
|
|
983
|
+
return this.executeOperation('update', // You can reuse 'update' action or add a new one like 'updateStatus'
|
|
984
|
+
() => this.currentOperations.updateStatus(id, status));
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* SHOW/HIDE form
|
|
988
|
+
* @param show Whether to show or hide the form
|
|
989
|
+
*/
|
|
990
|
+
showForm(show) {
|
|
991
|
+
this.showFormSignal.set(show);
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Update form action (create/edit)
|
|
995
|
+
* @param action The action to set for the form
|
|
996
|
+
*/
|
|
997
|
+
updateFormAction(action) {
|
|
998
|
+
this.formActionSignal.set(action);
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Shared operation execution logic
|
|
1002
|
+
*/
|
|
1003
|
+
executeOperation(action, operation, params) {
|
|
1004
|
+
this.errorSignal.set(null);
|
|
1005
|
+
this.loadingSignal.set(true);
|
|
1006
|
+
this.actionSignal.set(action);
|
|
1007
|
+
if (action === 'get') {
|
|
1008
|
+
this.currentParams = params;
|
|
1009
|
+
}
|
|
1010
|
+
const operation$ = operation().pipe(untilDestroyed(this), catchError((err) => {
|
|
1011
|
+
this.errorSignal.set(err);
|
|
1012
|
+
return of(null);
|
|
1013
|
+
}), finalize(() => {
|
|
1014
|
+
this.loadingSignal.set(false);
|
|
1015
|
+
this.actionSignal.set(null);
|
|
1016
|
+
}), shareReplay(1));
|
|
1017
|
+
if (action === 'get') {
|
|
1018
|
+
this.sourceSignal.set(operation$);
|
|
1019
|
+
}
|
|
1020
|
+
else {
|
|
1021
|
+
operation$.subscribe(() => {
|
|
1022
|
+
if (this.currentOperations?.get) {
|
|
1023
|
+
this.refresh();
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
return operation$;
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Refresh current data
|
|
1031
|
+
*/
|
|
1032
|
+
refresh() {
|
|
1033
|
+
if (this.currentOperations?.get && this.currentParams) {
|
|
1034
|
+
this.loadData(this.currentParams);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
get entityName() {
|
|
1038
|
+
return 'Item';
|
|
1039
|
+
}
|
|
1040
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CrudAbstractComponent, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1041
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CrudAbstractComponent });
|
|
1042
|
+
};
|
|
1043
|
+
CrudAbstractComponent = __decorate([
|
|
1044
|
+
UntilDestroy()
|
|
1045
|
+
], CrudAbstractComponent);
|
|
1046
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CrudAbstractComponent, decorators: [{
|
|
1047
|
+
type: Injectable
|
|
1048
|
+
}] });
|
|
1049
|
+
|
|
1050
|
+
class HelperService {
|
|
1051
|
+
transformEmployeeResponse = (res) => ({
|
|
1052
|
+
...res,
|
|
1053
|
+
results: res.results.map((e) => ({
|
|
1054
|
+
...e,
|
|
1055
|
+
fullName: [e.name.givenName, e.name.middleName, e.name.familyName]
|
|
1056
|
+
.filter((part) => part)
|
|
1057
|
+
.join(' ')
|
|
1058
|
+
.trim()
|
|
1059
|
+
.concat(e?.company?.name ? ` (${e.company.name})` : '')
|
|
1060
|
+
}))
|
|
1061
|
+
});
|
|
1062
|
+
transformPayloadWithAddress = (payload) => {
|
|
1063
|
+
const transformedPayload = { ...payload };
|
|
1064
|
+
if (transformedPayload['address']) {
|
|
1065
|
+
const address = { ...transformedPayload['address'] };
|
|
1066
|
+
// Helper function to extract name from address field
|
|
1067
|
+
const extractName = (field) => {
|
|
1068
|
+
if (!field)
|
|
1069
|
+
return undefined;
|
|
1070
|
+
if (typeof field === 'string')
|
|
1071
|
+
return field;
|
|
1072
|
+
if (typeof field === 'object' && field !== null && 'name' in field) {
|
|
1073
|
+
return field['name'];
|
|
1074
|
+
}
|
|
1075
|
+
return undefined;
|
|
1076
|
+
};
|
|
1077
|
+
address.province = extractName(address.province);
|
|
1078
|
+
address.city = extractName(address.city);
|
|
1079
|
+
address.barangay = extractName(address.barangay);
|
|
1080
|
+
transformedPayload['address'] = address;
|
|
1081
|
+
}
|
|
1082
|
+
return transformedPayload;
|
|
1083
|
+
};
|
|
1084
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HelperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1085
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HelperService, providedIn: 'root' });
|
|
1086
|
+
}
|
|
1087
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HelperService, decorators: [{
|
|
1088
|
+
type: Injectable,
|
|
1089
|
+
args: [{
|
|
1090
|
+
providedIn: 'root'
|
|
1091
|
+
}]
|
|
1092
|
+
}] });
|
|
1093
|
+
|
|
1094
|
+
// Components
|
|
1095
|
+
// export * from './lib/components/components';
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Generated bundle index. Do not edit.
|
|
1099
|
+
*/
|
|
1100
|
+
|
|
1101
|
+
export { BasicNgSelectComponent, CrudAbstractComponent, DataTableComponent, DynamicNgSelectComponent, EmptyComponent, FgAddressComponent, FileUploadComponent, FormFieldWrapperComponent, HelperService, PaginatedRequest };
|
|
1102
|
+
//# sourceMappingURL=winexist-ngp.mjs.map
|