@ldquocc/dynamic-form 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/ldquocc-dynamic-form.mjs +1013 -716
- package/fesm2022/ldquocc-dynamic-form.mjs.map +1 -1
- package/lib/shared/base/base-select.component.d.ts +19 -0
- package/lib/shared/base/base-value-accessor.d.ts +17 -10
- package/lib/shared/components/component.d.ts +2 -1
- package/lib/shared/components/field-user-config/field-user-config.component.d.ts +10 -0
- package/lib/shared/components/fields/date/date-picker/date-picker.component.d.ts +6 -4
- package/lib/shared/components/fields/date/date-range/date-range.component.d.ts +5 -4
- package/lib/shared/components/fields/input/input-formatted/input-formatted.component.d.ts +20 -0
- package/lib/shared/components/fields/input/input-password/input-password.component.d.ts +4 -3
- package/lib/shared/components/fields/input/input-text/input-text.component.d.ts +5 -5
- package/lib/shared/components/fields/select/multi-select/multi-select.component.d.ts +7 -11
- package/lib/shared/components/fields/select/single-select/single-select.component.d.ts +7 -12
- package/lib/shared/components/fields/select/tree-select/tree-select.component.d.ts +4 -3
- package/lib/shared/components/fields/textarea/textarea.component.d.ts +5 -4
- package/lib/shared/components/fields/upload/avatar-upload/avatar-upload.component.d.ts +12 -14
- package/lib/shared/components/fields/upload/multi-file-upload/multi-file-upload.component.d.ts +2 -4
- package/lib/shared/components/fields/upload/multi-image-upload/multi-image-upload.component.d.ts +10 -11
- package/lib/shared/components/fields/upload/single-file-upload/single-file-upload.component.d.ts +15 -16
- package/lib/shared/consts/common/common.const.d.ts +4 -0
- package/lib/shared/consts/fields/field.const.d.ts +1 -1
- package/lib/shared/consts/fields/index.d.ts +5 -4
- package/lib/shared/consts/fields/input-formatted-field.const.d.ts +4 -0
- package/lib/shared/enums/fields/field.enum.d.ts +1 -0
- package/lib/shared/enums/fields/index.d.ts +6 -5
- package/lib/shared/enums/fields/input-formatted-field.enum.d.ts +6 -0
- package/lib/shared/enums/validators/index.d.ts +2 -1
- package/lib/shared/enums/validators/regex.enum.d.ts +38 -0
- package/lib/shared/factories/auto-numeric-options.factory.d.ts +5 -0
- package/lib/shared/models/common/index.d.ts +7 -7
- package/lib/shared/models/fields/date/date-range-field.model.d.ts +3 -2
- package/lib/shared/models/fields/field-grid.model.d.ts +7 -7
- package/lib/shared/models/fields/field-user-config.model.d.ts +3 -0
- package/lib/shared/models/fields/field.model.d.ts +9 -7
- package/lib/shared/models/fields/index.d.ts +2 -0
- package/lib/shared/models/fields/input/index.d.ts +4 -3
- package/lib/shared/models/fields/input/input-formatted-field.model.d.ts +13 -0
- package/lib/shared/models/fields/select/select-base-field.model.d.ts +6 -6
- package/lib/shared/models/fields/upload/multi-image-upload-field.model.d.ts +1 -1
- package/lib/shared/services/field.service.d.ts +17 -5
- package/lib/shared/utils/dynamic-form/dynamic-form.d.ts +8 -4
- package/package.json +3 -4
- package/public-api.d.ts +2 -2
- package/styles/_common-form.scss +43 -0
- package/lib/shared/models/fields/index.model.d.ts +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as i1 from '@angular/forms';
|
|
2
2
|
import { FormsModule, ReactiveFormsModule, Validators, FormControl, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
3
|
-
import { of, delay, Subject, takeUntil, finalize, Observable, debounceTime, distinctUntilChanged } from 'rxjs';
|
|
3
|
+
import { of, delay, Subject, BehaviorSubject, takeUntil, combineLatest, finalize, Observable, debounceTime, distinctUntilChanged } from 'rxjs';
|
|
4
4
|
import * as i1$2 from '@angular/common';
|
|
5
5
|
import { CommonModule, CurrencyPipe } from '@angular/common';
|
|
6
6
|
import { RouterModule } from '@angular/router';
|
|
7
7
|
import * as i0 from '@angular/core';
|
|
8
|
-
import { InjectionToken, inject, Injectable, signal, untracked, input, computed, Input, Directive,
|
|
8
|
+
import { InjectionToken, inject, Injectable, signal, untracked, input, computed, effect, Input, Directive, forwardRef, Component, viewChild, EventEmitter, output, Output } from '@angular/core';
|
|
9
9
|
import * as i3$3 from 'ng-zorro-antd/form';
|
|
10
10
|
import { NzFormModule } from 'ng-zorro-antd/form';
|
|
11
11
|
import { isEqual } from 'lodash-es';
|
|
@@ -15,13 +15,16 @@ import * as i2 from 'ng-zorro-antd/date-picker';
|
|
|
15
15
|
import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
|
|
16
16
|
import * as i1$1 from 'ng-zorro-antd/input';
|
|
17
17
|
import { NzInputModule } from 'ng-zorro-antd/input';
|
|
18
|
-
import * as i3 from 'ng-zorro-antd/icon';
|
|
19
|
-
import { NzIconModule } from 'ng-zorro-antd/icon';
|
|
20
18
|
import * as i4 from 'ng-zorro-antd/button';
|
|
21
19
|
import { NzButtonModule } from 'ng-zorro-antd/button';
|
|
20
|
+
import * as i3 from 'ng-zorro-antd/icon';
|
|
21
|
+
import { NzIconModule } from 'ng-zorro-antd/icon';
|
|
22
22
|
import * as i5 from 'ng-zorro-antd/core/transition-patch';
|
|
23
23
|
import * as i6 from 'ng-zorro-antd/core/wave';
|
|
24
|
+
import AutoNumeric from '@zeedhi/autonumeric';
|
|
24
25
|
import { NgxCurrencyDirective } from 'ngx-currency';
|
|
26
|
+
import { toObservable, toSignal, rxResource } from '@angular/core/rxjs-interop';
|
|
27
|
+
import { map, switchMap, catchError } from 'rxjs/operators';
|
|
25
28
|
import * as i3$1 from 'ng-zorro-antd/select';
|
|
26
29
|
import { NzSelectModule } from 'ng-zorro-antd/select';
|
|
27
30
|
import * as i3$2 from 'ng-zorro-antd/spin';
|
|
@@ -31,14 +34,19 @@ import { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';
|
|
|
31
34
|
import * as i2$2 from 'ng-zorro-antd/upload';
|
|
32
35
|
import { NzUploadModule } from 'ng-zorro-antd/upload';
|
|
33
36
|
import { NzNotificationService } from 'ng-zorro-antd/notification';
|
|
34
|
-
import { ToastrService } from 'ngx-toastr';
|
|
35
|
-
import { TranslateService } from '@ngx-translate/core';
|
|
36
37
|
import { NzMessageService } from 'ng-zorro-antd/message';
|
|
37
38
|
import * as i7 from 'ng-zorro-antd/image';
|
|
38
39
|
import { NzImageModule } from 'ng-zorro-antd/image';
|
|
39
|
-
import * as i2$
|
|
40
|
+
import * as i2$4 from 'ng-zorro-antd/grid';
|
|
40
41
|
import { NzGridModule } from 'ng-zorro-antd/grid';
|
|
41
|
-
import * as
|
|
42
|
+
import * as i2$3 from 'ng-zorro-antd/dropdown';
|
|
43
|
+
import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
|
|
44
|
+
import * as i4$1 from 'ng-zorro-antd/switch';
|
|
45
|
+
import { NzSwitchModule } from 'ng-zorro-antd/switch';
|
|
46
|
+
import * as i1$3 from 'ng-zorro-antd/menu';
|
|
47
|
+
import * as i4$2 from 'ng-zorro-antd/flex';
|
|
48
|
+
import { NzFlexModule } from 'ng-zorro-antd/flex';
|
|
49
|
+
import * as i4$3 from 'ng-zorro-antd/collapse';
|
|
42
50
|
import { NzCollapseModule } from 'ng-zorro-antd/collapse';
|
|
43
51
|
|
|
44
52
|
// Core Angular modules (cần thiết ở hầu hết các component).
|
|
@@ -50,7 +58,11 @@ const ROUTING_MODULES = [RouterModule];
|
|
|
50
58
|
// 🧩 All common shared modules (nếu bạn muốn gộp nhanh)
|
|
51
59
|
const SHARED_MODULES = [...CORE_MODULES, ...FORM_MODULES, ...ROUTING_MODULES];
|
|
52
60
|
|
|
53
|
-
const NO_INFO_TEXT =
|
|
61
|
+
const NO_INFO_TEXT = "Không có thông tin";
|
|
62
|
+
const UPLOAD_FILE_TEXT = "Tải lên tập tin";
|
|
63
|
+
const NO_FILE_NAME = "Chưa có thông tin tên tập tin";
|
|
64
|
+
const UPLOAD_FILE_ERROR = "Lỗi trong quá trình tải tập tin đến máy chủ!";
|
|
65
|
+
const DELETE_FILE_ERROR = "Lỗi trong quá trình xóa tập tin đến máy chủ!";
|
|
54
66
|
|
|
55
67
|
const IMAGE_TYPES = {
|
|
56
68
|
apng: 'image/apng',
|
|
@@ -403,6 +415,55 @@ var CustomValidaterEnum;
|
|
|
403
415
|
CustomValidaterEnum["LeadingSpace"] = "leadingSpace";
|
|
404
416
|
})(CustomValidaterEnum || (CustomValidaterEnum = {}));
|
|
405
417
|
|
|
418
|
+
var RegexTypeEnum;
|
|
419
|
+
(function (RegexTypeEnum) {
|
|
420
|
+
RegexTypeEnum["Alpha"] = "^[a-zA-Z]+$";
|
|
421
|
+
RegexTypeEnum["AlphaNumeric"] = "^[a-zA-Z0-9]+$";
|
|
422
|
+
RegexTypeEnum["Name"] = "^[0-9a-zA-Z_ \u00C0\u00C1\u00C2\u00C3\u00C8\u00C9\u00CA\u00CC\u00CD\u00D2\u00D3\u00D4\u00D5\u00D9\u00DA\u0102\u0110\u0128\u0168\u01A0\u00E0\u00E1\u00E2\u00E3\u00E8\u00E9\u00EA\u00EC\u00ED\u00F2\u00F3\u00F4\u00F5\u00F9\u00FA\u0103\u0111\u0129\u0169\u01A1\u01AF\u0102\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EC0\u1EC0\u1EC2\u1EBE\u01B0\u0103\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EC1\u1EC1\u1EC3\u1EBF\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u00DD\u1EF6\u1EF8\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u00FD\u1EF7\u1EF9\\.+,:%&=;s.\\/\\-_'\\()]+$";
|
|
423
|
+
RegexTypeEnum["Username"] = "^[a-z0-9_.s]+$";
|
|
424
|
+
RegexTypeEnum["RegexPostCode"] = "^[a-zA-Z0-9-s]+$";
|
|
425
|
+
RegexTypeEnum["AlphaDash"] = "^[a-zA-Z0-9_-s.]+$";
|
|
426
|
+
RegexTypeEnum["AlphaVN"] = "^[a-zA-Z_ \u00C0\u00C1\u00C2\u00C3\u00C8\u00C9\u00CA\u00CC\u00CD\u00D2\u00D3\u00D4\u00D5\u00D9\u00DA\u0102\u0110\u0128\u0168\u01A0\u00E0\u00E1\u00E2\u00E3\u00E8\u00E9\u00EA\u00EC\u00ED\u00F2\u00F3\u00F4\u00F5\u00F9\u00FA\u0103\u0111\u0129\u0169\u01A1\u01AF\u0102\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EC0\u1EC0\u1EC2\u1EBE\u01B0\u0103\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EC1\u1EC1\u1EC3\u1EBF\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u00DD\u1EF6\u1EF8\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u00FD\u1EF7\u1EF9\\,s]+$";
|
|
427
|
+
RegexTypeEnum["AlphaNumericVN"] = "^[0-9a-zA-Z_ \u00C0\u00C1\u00C2\u00C3\u00C8\u00C9\u00CA\u00CC\u00CD\u00D2\u00D3\u00D4\u00D5\u00D9\u00DA\u0102\u0110\u0128\u0168\u01A0\u00E0\u00E1\u00E2\u00E3\u00E8\u00E9\u00EA\u00EC\u00ED\u00F2\u00F3\u00F4\u00F5\u00F9\u00FA\u0103\u0111\u0129\u0169\u01A1\u01AF\u0102\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EC0\u1EC0\u1EC2\u1EBE\u01B0\u0103\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EC1\u1EC1\u1EC3\u1EBF\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u00DD\u1EF6\u1EF8\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u00FD\u1EF7\u1EF9\\s]+$";
|
|
428
|
+
RegexTypeEnum["AlphaDashVN"] = "^[0-9a-zA-Z_ \u00C0\u00C1\u00C2\u00C3\u00C8\u00C9\u00CA\u00CC\u00CD\u00D2\u00D3\u00D4\u00D5\u00D9\u00DA\u0102\u0110\u0128\u0168\u01A0\u00E0\u00E1\u00E2\u00E3\u00E8\u00E9\u00EA\u00EC\u00ED\u00F2\u00F3\u00F4\u00F5\u00F9\u00FA\u0103\u0111\u0129\u0169\u01A1\u01AF\u0102\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EC0\u1EC0\u1EC2\u1EBE\u01B0\u0103\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EC1\u1EC1\u1EC3\u1EBF\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u00DD\u1EF6\u1EF8\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u00FD\u1EF7\u1EF9\\.+,:%&=;s.\\/\\-_'\\()]+$";
|
|
429
|
+
RegexTypeEnum["UnitName"] = "^[a-zA-Z0-9 \u00C0\u00C1\u00C2\u00C3\u00C8\u00C9\u00CA\u00CC\u00CD\u00D2\u00D3\u00D4\u00D5\u00D9\u00DA\u0102\u0110\u0128\u0168\u01A0\u00E0\u00E1\u00E2\u00E3\u00E8\u00E9\u00EA\u00EC\u00ED\u00F2\u00F3\u00F4\u00F5\u00F9\u00FA\u0103\u0111\u0129\u0169\u01A1\u01AF\u0102\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EC0\u1EC0\u1EC2\u1EBE\u01B0\u0103\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EC1\u1EC1\u1EC3\u1EBF\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u00DD\u1EF6\u1EF8\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9s_-]+$";
|
|
430
|
+
RegexTypeEnum["Date"] = "([12]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01]))";
|
|
431
|
+
RegexTypeEnum["Time"] = "(?=[01]\\d|2[0123])=(?=[012345]\\d)=(?=[012345]\\d)";
|
|
432
|
+
RegexTypeEnum["DateTime"] = "[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) (2[0-3]|[01][0-9])=[0-5][0-9]=[0-5][0-9]";
|
|
433
|
+
// dateVN= "^(0?[1-9]|[12][0-9]|3[01])[\\/](0?[1-9]|1[012])[\\/]\\d{4}$",
|
|
434
|
+
// dateVN= /^(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-](19|20)\d\d/,
|
|
435
|
+
// dateVN= "^([0-2][0-9]|(3)[0-1])(\-)(((0)[0-9])|((1)[0-2]))(\-)\d{4}$",
|
|
436
|
+
RegexTypeEnum["DateVN"] = "^(?=0[1-9]|[12]d|3[01])([/.-])(?=0[1-9]|1[012])\\1(?=19|20)dd$";
|
|
437
|
+
RegexTypeEnum["DateTimeVN"] = "^(0?[1-9]|[12][0-9]|3[01])[\\/](0?[1-9]|1[012])[\\/]\\d{4} (\\d{2})=(\\d{2})=(\\d{2})$";
|
|
438
|
+
RegexTypeEnum["DateShortTimeVN"] = "^(0?[1-9]|[12][0-9]|3[01])[\\/](0?[1-9]|1[012])[\\/]\\d{4} (\\d{2})=(\\d{2})$";
|
|
439
|
+
RegexTypeEnum["Integer"] = "^\\-?[0-9]+$";
|
|
440
|
+
RegexTypeEnum["Decimal"] = "^\\-?[0-9]*\\.?[0-9]+$";
|
|
441
|
+
RegexTypeEnum["IpAddress"] = "^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})$";
|
|
442
|
+
RegexTypeEnum["Base64"] = "[^a-zA-Z0-9\\/\\+=]";
|
|
443
|
+
RegexTypeEnum["Indentityid"] = "^\\d{12}$";
|
|
444
|
+
// dnkhcn = "/^DNKHCN-[A-Z]{2}-d{4}$/",
|
|
445
|
+
// msdn = "/^d{10}$/",
|
|
446
|
+
RegexTypeEnum["IntergerNotZero"] = "^[0-9]*[1-9][0-9]*$";
|
|
447
|
+
//link = "(https?=//(?=www.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9].[^s]{2,}|www.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9].[^s]{2,}|https?=//(?=www.|(?!www))[a-zA-Z0-9]+.[^s]{2,}|www.[a-zA-Z0-9]+.[^s]{2,})",
|
|
448
|
+
// code = "^['A-Z''0-9''._\\-']*$",
|
|
449
|
+
RegexTypeEnum["Code"] = "^['A-Z''0-9''./_\\-\\/\\\u0110']*$";
|
|
450
|
+
RegexTypeEnum["CodeHsda"] = "^['A-Z''0-9''./_\\-']*$";
|
|
451
|
+
RegexTypeEnum["LinkLocation"] = "(https?://)?([\\da-z.-]+)\\.([a-z.]{2,6})([/\\w .-]*)?(\\?[\\w=&,.%-]*)?";
|
|
452
|
+
RegexTypeEnum["Link"] = "(https?://)?([\\da-z.-]+)\\.([a-z.]{2,6})[/\\w .-]*/?";
|
|
453
|
+
//password = "/(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[$@$!%*?&]).{8,}/",
|
|
454
|
+
RegexTypeEnum["AccountName"] = "^[a-zA-Z0-9_.]{2,20}$";
|
|
455
|
+
RegexTypeEnum["NameOrFullName"] = "^[a-zA-Z0-9_\u00C0\u00C1\u00C2\u00C3\u00C8\u00C9\u00CA\u00CC\u00CD\u00D2\u00D3\u00D4\u00D5\u00D9\u00DA\u0102\u0110\u0128\u0168\u01A0\u00E0\u00E1\u00E2\u00E3\u00E8\u00E9\u00EA\u00EC\u00ED\u00F2\u00F3\u00F4\u00F5\u00F9\u00FA\u0103\u0111\u0129\u0169\u01A1\u01AF\u0102\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EC0\u1EC0\u1EC2\u01B0\u0103\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EC1\u1EC1\u1EC3\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EC5\u1EBF\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u00DD\u1EF6\u1EF8\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9 ]{1,20}$";
|
|
456
|
+
RegexTypeEnum["PackageName"] = "^(?:[a-zA-Z]+(?:d*[a-zA-Z_]*)*)(?:.[a-zA-Z]+(?:d*[a-zA-Z_]*)*)+$";
|
|
457
|
+
RegexTypeEnum["Email"] = "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$";
|
|
458
|
+
RegexTypeEnum["PasswordRegex"] = "^(?!.*\\s)(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[~`!@#$%^&*()--+={}\\[\\]|\\\\:;\"'<>,.?/_\u20B9]).{8,}$";
|
|
459
|
+
// phoneNumber = "^(\\+84|0)([235789])([0-9]{8,9})\\b",
|
|
460
|
+
RegexTypeEnum["PhoneNumber"] = "^(\\+84|0)([235789])([0-9]{8,9})$";
|
|
461
|
+
RegexTypeEnum["SeqNum"] = "^(100|[0-9]{1,2})$";
|
|
462
|
+
RegexTypeEnum["LinkBasemap"] = "(https://www.|http://www.|https://|http://)?[a-zA-Z]{2,}(.[a-zA-Z]{2,})(.[a-zA-Z]{2,})?/[a-zA-Z0-9]{2,}|((https://www.|http://www.|https://|http://)?[a-zA-Z]{2,}(.[a-zA-Z]{2,})(.[a-zA-Z]{2,})?)|(https://www.|http://www.|https://|http://)?[a-zA-Z0-9]{2,}.[a-zA-Z0-9]{2,}.[a-zA-Z0-9]{2,}(.[a-zA-Z0-9]{2,})?";
|
|
463
|
+
RegexTypeEnum["AlphaDashBreakLineVN"] = "^[0-9a-zA-Z_ \u00C0\u00C1\u00C2\u00C3\u00C8\u00C9\u00CA\u00CC\u00CD\u00D2\u00D3\u00D4\u00D5\u00D9\u00DA\u0102\u0110\u0128\u0168\u01A0\u00E0\u00E1\u00E2\u00E3\u00E8\u00E9\u00EA\u00EC\u00ED\u00F2\u00F3\u00F4\u00F5\u00F9\u00FA\u0103\u0111\u0129\u0169\u01A1\u01AF\u0102\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EC0\u1EC0\u1EC2\u1EBE\u01B0\u0103\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EC1\u1EC1\u1EC3\u1EBF\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u00DD\u1EF6\u1EF8\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u00FD\u1EF7\u1EF9\\.+,:%&=;s.\\/\\-_'\\(\\)\n]+$";
|
|
464
|
+
RegexTypeEnum["Fax"] = "^(\\+?\\d{1,4}[\\s-]?)?(\\(?\\d{2,4}\\)?[\\s-]?)?[\\d\\s-]{5,15}$";
|
|
465
|
+
})(RegexTypeEnum || (RegexTypeEnum = {}));
|
|
466
|
+
|
|
406
467
|
var FormModeEnum;
|
|
407
468
|
(function (FormModeEnum) {
|
|
408
469
|
FormModeEnum["Add"] = "add";
|
|
@@ -461,7 +522,7 @@ class BaseField {
|
|
|
461
522
|
// Thứ tự hiển thị của field
|
|
462
523
|
this.seqNum = 0;
|
|
463
524
|
if (!init?.key || !init?.label) {
|
|
464
|
-
throw new Error(
|
|
525
|
+
throw new Error("key, label, and type are required");
|
|
465
526
|
}
|
|
466
527
|
/**
|
|
467
528
|
* Gán giá trị cho các props cần giá trị mặc định ở BaseField.
|
|
@@ -471,11 +532,15 @@ class BaseField {
|
|
|
471
532
|
this.grid = { xs: 24 };
|
|
472
533
|
this.labelGrid = { xs: 24 };
|
|
473
534
|
this.controlGrid = { xs: 24 };
|
|
474
|
-
this.labelAlign =
|
|
535
|
+
this.labelAlign = "left";
|
|
475
536
|
this.isHidden = false;
|
|
476
537
|
this.isDisabled = false;
|
|
477
538
|
this.isParent = false;
|
|
478
|
-
this.allowSetValue = [
|
|
539
|
+
this.allowSetValue = [
|
|
540
|
+
FormModeEnum.Add,
|
|
541
|
+
FormModeEnum.Edit,
|
|
542
|
+
FormModeEnum.View,
|
|
543
|
+
];
|
|
479
544
|
this.viewMode = ViewModeEnum.form;
|
|
480
545
|
this.enableFieldChange = false;
|
|
481
546
|
Object.assign(this, init);
|
|
@@ -496,14 +561,14 @@ class BaseField {
|
|
|
496
561
|
}
|
|
497
562
|
getErrorMessage(errorKey, errorValue, allFields) {
|
|
498
563
|
if (errorKey === CommonValidaterEnum.Required) {
|
|
499
|
-
return `${this.label ||
|
|
564
|
+
return `${this.label || "Trường này"} là bắt buộc`;
|
|
500
565
|
}
|
|
501
566
|
if (errorKey === CustomValidaterEnum.MatchField) {
|
|
502
567
|
const matchKey = this.matchField;
|
|
503
|
-
const targetLabel = allFields.find(f => f.key === matchKey)?.label || matchKey;
|
|
568
|
+
const targetLabel = allFields.find((f) => f.key === matchKey)?.label || matchKey;
|
|
504
569
|
return `${this.label} không khớp với ${targetLabel}`;
|
|
505
570
|
}
|
|
506
|
-
return
|
|
571
|
+
return "";
|
|
507
572
|
}
|
|
508
573
|
}
|
|
509
574
|
|
|
@@ -761,6 +826,7 @@ var FieldTypeEnum;
|
|
|
761
826
|
(function (FieldTypeEnum) {
|
|
762
827
|
FieldTypeEnum["InputText"] = "input-text";
|
|
763
828
|
FieldTypeEnum["InputPassword"] = "input-password";
|
|
829
|
+
FieldTypeEnum["InputFormatted"] = "input-formatted";
|
|
764
830
|
FieldTypeEnum["Textarea"] = "textarea";
|
|
765
831
|
FieldTypeEnum["DatePicker"] = "date-picker";
|
|
766
832
|
FieldTypeEnum["DateRange"] = "date-range";
|
|
@@ -786,6 +852,14 @@ var InputFieldTypeEnum;
|
|
|
786
852
|
InputFieldTypeEnum["Number"] = "number";
|
|
787
853
|
})(InputFieldTypeEnum || (InputFieldTypeEnum = {}));
|
|
788
854
|
|
|
855
|
+
var NumericPreset;
|
|
856
|
+
(function (NumericPreset) {
|
|
857
|
+
NumericPreset["Integer"] = "integer";
|
|
858
|
+
NumericPreset["Decimal"] = "decimal";
|
|
859
|
+
NumericPreset["Currency"] = "currency";
|
|
860
|
+
NumericPreset["Manual"] = "manual";
|
|
861
|
+
})(NumericPreset || (NumericPreset = {}));
|
|
862
|
+
|
|
789
863
|
var DateFieldTypeEnum;
|
|
790
864
|
(function (DateFieldTypeEnum) {
|
|
791
865
|
DateFieldTypeEnum["Picker"] = "picker";
|
|
@@ -855,6 +929,30 @@ class InputPasswordField extends InputBaseField {
|
|
|
855
929
|
}
|
|
856
930
|
}
|
|
857
931
|
|
|
932
|
+
/**
|
|
933
|
+
* Interface của Input Field dạng format.
|
|
934
|
+
*/
|
|
935
|
+
class InputFormattedField extends InputBaseField {
|
|
936
|
+
constructor(init) {
|
|
937
|
+
super(init);
|
|
938
|
+
/**
|
|
939
|
+
* Gán giá trị cho các props cần giá trị mặc định ở InputFormatted.
|
|
940
|
+
*/
|
|
941
|
+
this.type = FieldTypeEnum.InputFormatted;
|
|
942
|
+
this.format = NumericPreset.Integer;
|
|
943
|
+
Object.assign(this, init);
|
|
944
|
+
}
|
|
945
|
+
// Tạo Form Control cho Input Formatted Field.
|
|
946
|
+
toFormControl() {
|
|
947
|
+
const commonValidators = this.getInputCommonValidators();
|
|
948
|
+
const customValidators = this.getInputCustomValidators();
|
|
949
|
+
return new FormControl(this.value ?? "", [
|
|
950
|
+
...commonValidators,
|
|
951
|
+
...customValidators,
|
|
952
|
+
]);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
858
956
|
const buildForm = (fields, mode, model) => {
|
|
859
957
|
const groupObj = {};
|
|
860
958
|
// console.log("model", model);
|
|
@@ -889,6 +987,34 @@ const buildForm = (fields, mode, model) => {
|
|
|
889
987
|
}
|
|
890
988
|
return new FormGroup(groupObj);
|
|
891
989
|
};
|
|
990
|
+
// Tạo tự động placeholder cho các dạng control nhập với label hoặc key từ field
|
|
991
|
+
const createInputPlaceholder = (field) => {
|
|
992
|
+
const label = field?.label;
|
|
993
|
+
if (label)
|
|
994
|
+
return `Nhập ${label?.toLowerCase()}`;
|
|
995
|
+
return `Nhập ${field.key?.toLowerCase()}`;
|
|
996
|
+
};
|
|
997
|
+
// Tạo tự động placeholder cho các dạng single select với label hoặc key từ field
|
|
998
|
+
const createSingleSelectPlaceholder = (field) => {
|
|
999
|
+
const label = field?.label;
|
|
1000
|
+
if (label)
|
|
1001
|
+
return `Chọn ${label?.toLowerCase()}`;
|
|
1002
|
+
return `Chọn ${field.key?.toLowerCase()}`;
|
|
1003
|
+
};
|
|
1004
|
+
// Tạo tự động placeholder cho các dạng multi select với label hoặc key từ field
|
|
1005
|
+
const createMultiSelectPlaceholder = (field) => {
|
|
1006
|
+
const label = field?.label;
|
|
1007
|
+
if (label)
|
|
1008
|
+
return `Chọn các ${label?.toLowerCase()}`;
|
|
1009
|
+
return `Chọn các ${field.key?.toLowerCase()}`;
|
|
1010
|
+
};
|
|
1011
|
+
// Tạo tự động placeholder cho các dạng date-picker với label hoặc key từ field
|
|
1012
|
+
const createDatePickerPlaceholder = (field) => {
|
|
1013
|
+
const label = field?.label;
|
|
1014
|
+
if (label)
|
|
1015
|
+
return `Chọn ${label?.toLowerCase()}`;
|
|
1016
|
+
return `Chọn ${field.key?.toLowerCase()}`;
|
|
1017
|
+
};
|
|
892
1018
|
// Tạo placeholder mặc định cho các dạng Input, Textarea.
|
|
893
1019
|
const createPlaceholder = (field) => {
|
|
894
1020
|
const placeholder = field?.placeholder;
|
|
@@ -907,7 +1033,7 @@ const createSelectPlaceholder = (field) => {
|
|
|
907
1033
|
const label = field?.label;
|
|
908
1034
|
if (label) {
|
|
909
1035
|
const isSingleSelect = field?.type === FieldTypeEnum.SingleSelect;
|
|
910
|
-
return `Chọn ${isSingleSelect ?
|
|
1036
|
+
return `Chọn ${isSingleSelect ? "" : "các"} ${label?.toLowerCase()}`;
|
|
911
1037
|
}
|
|
912
1038
|
return `Nhập ${field.key?.toLowerCase()}`;
|
|
913
1039
|
};
|
|
@@ -1067,7 +1193,10 @@ class SelectBaseField extends BaseField {
|
|
|
1067
1193
|
toFormControl() {
|
|
1068
1194
|
const commonValidators = this.getCommonSelectValidators();
|
|
1069
1195
|
const customValidators = this.getCustomSelectValidators();
|
|
1070
|
-
return new FormControl(this.value ??
|
|
1196
|
+
return new FormControl(this.value ?? "", [
|
|
1197
|
+
...commonValidators,
|
|
1198
|
+
...customValidators,
|
|
1199
|
+
]);
|
|
1071
1200
|
}
|
|
1072
1201
|
getErrorMessage(errorKey, errorValue, allFields) {
|
|
1073
1202
|
return super.getErrorMessage(errorKey, errorValue, allFields);
|
|
@@ -1174,23 +1303,24 @@ class BaseDateField extends BaseField {
|
|
|
1174
1303
|
* FIELD_TYPES là readonly ['input', 'select', 'checkbox',...]
|
|
1175
1304
|
*/
|
|
1176
1305
|
const FIELD_TYPES = [
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1306
|
+
"input-text",
|
|
1307
|
+
"input-password",
|
|
1308
|
+
"input-formatted",
|
|
1309
|
+
"textarea",
|
|
1310
|
+
"date-picker",
|
|
1311
|
+
"date-range",
|
|
1312
|
+
"single-select",
|
|
1313
|
+
"tree-select",
|
|
1314
|
+
"multi-select",
|
|
1315
|
+
"single-file-upload",
|
|
1316
|
+
"multi-file-upload",
|
|
1317
|
+
"multi-image-upload",
|
|
1318
|
+
"avatar-upload",
|
|
1319
|
+
"checkbox",
|
|
1320
|
+
"radio",
|
|
1321
|
+
"reminder-type-radio",
|
|
1322
|
+
"switch",
|
|
1323
|
+
"autocomplete",
|
|
1194
1324
|
];
|
|
1195
1325
|
|
|
1196
1326
|
/**
|
|
@@ -1208,6 +1338,33 @@ const FORMAT_DATE_PATTERNS = {
|
|
|
1208
1338
|
MM_DD_YYYY_HMS: /^(0[1-9]|1[0-2])([-\/])(0[1-9]|[12]\d|3[01])\2(\d{4})\s([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$/,
|
|
1209
1339
|
};
|
|
1210
1340
|
|
|
1341
|
+
const BASE_OPTIONS = {
|
|
1342
|
+
modifyValueOnWheel: false,
|
|
1343
|
+
selectOnFocus: false,
|
|
1344
|
+
};
|
|
1345
|
+
const NUMERIC_PRESETS = {
|
|
1346
|
+
[NumericPreset.Integer]: {
|
|
1347
|
+
digitGroupSeparator: ".",
|
|
1348
|
+
decimalCharacter: ",",
|
|
1349
|
+
decimalPlaces: 0,
|
|
1350
|
+
minimumValue: "0",
|
|
1351
|
+
},
|
|
1352
|
+
[NumericPreset.Decimal]: {
|
|
1353
|
+
digitGroupSeparator: ".",
|
|
1354
|
+
decimalCharacter: ",",
|
|
1355
|
+
decimalPlaces: 2,
|
|
1356
|
+
minimumValue: "0",
|
|
1357
|
+
},
|
|
1358
|
+
[NumericPreset.Currency]: {
|
|
1359
|
+
digitGroupSeparator: ".",
|
|
1360
|
+
decimalCharacter: ",",
|
|
1361
|
+
decimalPlaces: 0,
|
|
1362
|
+
currencySymbol: " ₫",
|
|
1363
|
+
currencySymbolPlacement: "s",
|
|
1364
|
+
minimumValue: "0",
|
|
1365
|
+
},
|
|
1366
|
+
};
|
|
1367
|
+
|
|
1211
1368
|
// Chuyển đổi đối tượng Date thành string có format DDMMYYYY.
|
|
1212
1369
|
const formatDateToDDMMYYYY = (date, separator = '-') => {
|
|
1213
1370
|
const dd = String(date.getDate()).padStart(2, '0');
|
|
@@ -1379,8 +1536,8 @@ class DateRangeField extends BaseDateField {
|
|
|
1379
1536
|
}
|
|
1380
1537
|
toFormValue(modelValue) {
|
|
1381
1538
|
let value = modelValue;
|
|
1382
|
-
if (typeof value ===
|
|
1383
|
-
value = value.split(
|
|
1539
|
+
if (typeof value === "string") {
|
|
1540
|
+
value = value.split(",").map((dateStr) => dateStr.trim());
|
|
1384
1541
|
}
|
|
1385
1542
|
let dateRange = [];
|
|
1386
1543
|
if (value?.length === 2) {
|
|
@@ -1495,7 +1652,7 @@ class MultiFileUploadField extends BaseUploadField {
|
|
|
1495
1652
|
}
|
|
1496
1653
|
}
|
|
1497
1654
|
|
|
1498
|
-
const DEFAULT_MULTI_IMAGE_UPLOAD_VALUE =
|
|
1655
|
+
const DEFAULT_MULTI_IMAGE_UPLOAD_VALUE = "";
|
|
1499
1656
|
/**
|
|
1500
1657
|
* Interface của Multi image upload.
|
|
1501
1658
|
*/
|
|
@@ -1509,8 +1666,8 @@ class MultiImageUploadField extends BaseUploadField {
|
|
|
1509
1666
|
this.value = DEFAULT_MULTI_IMAGE_UPLOAD_VALUE;
|
|
1510
1667
|
this.initialValue = DEFAULT_MULTI_IMAGE_UPLOAD_VALUE;
|
|
1511
1668
|
this.maxFileCount = 6;
|
|
1512
|
-
this.imageCardWidth =
|
|
1513
|
-
this.imageCardHeight =
|
|
1669
|
+
this.imageCardWidth = "108px";
|
|
1670
|
+
this.imageCardHeight = "108px";
|
|
1514
1671
|
Object.assign(this, init);
|
|
1515
1672
|
}
|
|
1516
1673
|
getDefaultValue() {
|
|
@@ -1863,7 +2020,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
1863
2020
|
class FieldService {
|
|
1864
2021
|
constructor() {
|
|
1865
2022
|
this.httpClient = inject(HttpClient);
|
|
2023
|
+
// =========================================================================
|
|
2024
|
+
// --- CODE CŨ (Sử dụng Signal cho luồng phụ thuộc) ---
|
|
2025
|
+
// =========================================================================
|
|
1866
2026
|
this.dependValuesMap = new Map();
|
|
2027
|
+
// =========================================================================
|
|
2028
|
+
// --- CODE MỚI (Sử dụng RxJS BehaviorSubject cho luồng phụ thuộc) ---
|
|
2029
|
+
// =========================================================================
|
|
2030
|
+
// Giải thích kiến trúc mới:
|
|
2031
|
+
// - Dùng BehaviorSubject vì nó lưu lại giá trị cuối cùng. Khi một field Con
|
|
2032
|
+
// được khởi tạo sau field Cha và subscribe vào, nó sẽ lập tức nhận được
|
|
2033
|
+
// giá trị hiện hành thay vì phải chờ Cha thay đổi lần nữa.
|
|
2034
|
+
// - Cách này giúp thiết lập luồng dữ liệu dạng Push, rất dễ dàng kết hợp
|
|
2035
|
+
// với rxResource hoặc switchMap ở phía Component Con để triệt tiêu lỗi Race-condition.
|
|
2036
|
+
this.dependValuesSubjectMap = new Map();
|
|
1867
2037
|
// Signal lưu trữ đối tượng chứa các prop là fieldKey có isParent là true.
|
|
1868
2038
|
this.dependValues = signal({});
|
|
1869
2039
|
// Signal lưu giữ xem field có isParent gần nhất vừa change giá trị.
|
|
@@ -1889,9 +2059,33 @@ class FieldService {
|
|
|
1889
2059
|
getDependValuesMap() {
|
|
1890
2060
|
return this.dependValuesMap;
|
|
1891
2061
|
}
|
|
2062
|
+
/**
|
|
2063
|
+
* Bắn (Emit) giá trị thay đổi của một trường Parent vào stream.
|
|
2064
|
+
* Sẽ được gọi bởi Component đóng vai trò là Cha (isParent = true).
|
|
2065
|
+
*/
|
|
2066
|
+
emitDependValueChange(key, value) {
|
|
2067
|
+
if (!this.dependValuesSubjectMap.has(key)) {
|
|
2068
|
+
this.dependValuesSubjectMap.set(key, new BehaviorSubject(value));
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
// Nếu đã có stream, đẩy giá trị mới vào ống nước.
|
|
2072
|
+
this.dependValuesSubjectMap.get(key).next(value);
|
|
2073
|
+
}
|
|
2074
|
+
/**
|
|
2075
|
+
* Trả về Observable của một trường để các Component Con có thể subscribe/nghe ngóng.
|
|
2076
|
+
* Sẽ được gọi bởi các Component có chứa `dependsOn`.
|
|
2077
|
+
*/
|
|
2078
|
+
getDependValueChanges$(key) {
|
|
2079
|
+
if (!this.dependValuesSubjectMap.has(key)) {
|
|
2080
|
+
// Đề phòng trường hợp Con subscribe trước khi Cha khởi tạo (hoặc Cha chưa patch value)
|
|
2081
|
+
// Ta tạo sẵn một ống nước rỗng với giá trị ban đầu là null.
|
|
2082
|
+
this.dependValuesSubjectMap.set(key, new BehaviorSubject(null));
|
|
2083
|
+
}
|
|
2084
|
+
return this.dependValuesSubjectMap.get(key).asObservable();
|
|
2085
|
+
}
|
|
1892
2086
|
// Cập nhật giá trị theo key vào đối tượng của signal.
|
|
1893
2087
|
updateDependValues(key, value) {
|
|
1894
|
-
this.dependValues.update(curr => ({ ...curr, [key]: value }));
|
|
2088
|
+
this.dependValues.update((curr) => ({ ...curr, [key]: value }));
|
|
1895
2089
|
}
|
|
1896
2090
|
// Xóa giá trị và loại bỏ key theo key khỏi đối tượng của signal.
|
|
1897
2091
|
removeDependValues(key) {
|
|
@@ -1925,12 +2119,12 @@ class FieldService {
|
|
|
1925
2119
|
});
|
|
1926
2120
|
}
|
|
1927
2121
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FieldService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1928
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FieldService, providedIn:
|
|
2122
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FieldService, providedIn: "root" }); }
|
|
1929
2123
|
}
|
|
1930
2124
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FieldService, decorators: [{
|
|
1931
2125
|
type: Injectable,
|
|
1932
2126
|
args: [{
|
|
1933
|
-
providedIn:
|
|
2127
|
+
providedIn: "root",
|
|
1934
2128
|
}]
|
|
1935
2129
|
}] });
|
|
1936
2130
|
|
|
@@ -2048,22 +2242,44 @@ class BaseValueAccessor {
|
|
|
2048
2242
|
this.control = null;
|
|
2049
2243
|
// Chế độ form: Add, Edit, View...
|
|
2050
2244
|
this.modeSignal = input(FormModeEnum.Add);
|
|
2051
|
-
this.isAdd = computed(() => this.modeSignal() ===
|
|
2052
|
-
this.isEdit = computed(() => this.modeSignal() ===
|
|
2053
|
-
this.isView = computed(() => this.modeSignal() ===
|
|
2054
|
-
this.isAddOrEdit = computed(() => [
|
|
2055
|
-
this.isEditOrView = computed(() => [
|
|
2245
|
+
this.isAdd = computed(() => this.modeSignal() === "add");
|
|
2246
|
+
this.isEdit = computed(() => this.modeSignal() === "edit");
|
|
2247
|
+
this.isView = computed(() => this.modeSignal() === "view");
|
|
2248
|
+
this.isAddOrEdit = computed(() => ["add", "edit"].includes(this.modeSignal()));
|
|
2249
|
+
this.isEditOrView = computed(() => ["edit", "view"].includes(this.modeSignal()));
|
|
2056
2250
|
this.formModeEnum = FormModeEnum;
|
|
2057
2251
|
this.viewModeEnum = ViewModeEnum;
|
|
2058
2252
|
this.destroy$ = new Subject();
|
|
2059
2253
|
// Dành cho ControlValueAccessor.
|
|
2060
2254
|
this.value = null;
|
|
2255
|
+
this.valueSignal = signal(null);
|
|
2061
2256
|
this.onChange = () => { };
|
|
2062
2257
|
this.onTouched = () => { };
|
|
2063
2258
|
this.isDisabled = false;
|
|
2259
|
+
this.disabledSignal = signal(false); // Đang có select dùng isDisableSignal nên sau này đồng bộ lại.
|
|
2064
2260
|
this.dFormService = inject(DynamicFormService);
|
|
2065
2261
|
this.formDataService = inject(FormDataService);
|
|
2066
2262
|
this.fieldService = inject(FieldService);
|
|
2263
|
+
this.resetEffect = effect(() => {
|
|
2264
|
+
const reset = this.dFormService.resetTrigger();
|
|
2265
|
+
if (reset?.formId === this.formId) {
|
|
2266
|
+
this.reset();
|
|
2267
|
+
}
|
|
2268
|
+
});
|
|
2269
|
+
// Dành cho UI
|
|
2270
|
+
this.viewMode = computed(() => this.fieldInput().viewMode);
|
|
2271
|
+
this.displayPlaceholder = computed(() => {
|
|
2272
|
+
if (!this.isAddOrEdit())
|
|
2273
|
+
return "";
|
|
2274
|
+
const placeholder = this.fieldInput()?.placeholder;
|
|
2275
|
+
if (placeholder)
|
|
2276
|
+
return placeholder;
|
|
2277
|
+
return this.resolvePlaceholderText();
|
|
2278
|
+
});
|
|
2279
|
+
}
|
|
2280
|
+
// 2. Hàm sinh text mặc định (Component con có thể override hàm này)
|
|
2281
|
+
resolvePlaceholderText() {
|
|
2282
|
+
return "Nhập dữ liệu";
|
|
2067
2283
|
}
|
|
2068
2284
|
ngOnDestroy() {
|
|
2069
2285
|
this.destroy$.next();
|
|
@@ -2074,6 +2290,7 @@ class BaseValueAccessor {
|
|
|
2074
2290
|
}
|
|
2075
2291
|
writeValue(value) {
|
|
2076
2292
|
this.value = value;
|
|
2293
|
+
this.valueSignal.set(value);
|
|
2077
2294
|
this.writeValueToView(value); // 👈 component con override nếu cần.
|
|
2078
2295
|
}
|
|
2079
2296
|
registerOnChange(fn) {
|
|
@@ -2084,10 +2301,13 @@ class BaseValueAccessor {
|
|
|
2084
2301
|
}
|
|
2085
2302
|
setDisabledState(isDisabled) {
|
|
2086
2303
|
this.isDisabled = isDisabled;
|
|
2304
|
+
this.disabledSignal.set(isDisabled);
|
|
2087
2305
|
this.setDisabledOnView(isDisabled);
|
|
2088
2306
|
}
|
|
2089
2307
|
propagateValue(value) {
|
|
2090
2308
|
this.value = value;
|
|
2309
|
+
this.valueSignal.set(value);
|
|
2310
|
+
this.fieldService.onFieldChange(this.fieldKey(), value);
|
|
2091
2311
|
this.onChange(this.value);
|
|
2092
2312
|
// Khi thay đổi value.
|
|
2093
2313
|
this.handleValueChange(value);
|
|
@@ -2128,6 +2348,9 @@ class BaseValueAccessor {
|
|
|
2128
2348
|
enableControl() {
|
|
2129
2349
|
this.control?.enable();
|
|
2130
2350
|
}
|
|
2351
|
+
resetControl() {
|
|
2352
|
+
this.control?.reset();
|
|
2353
|
+
}
|
|
2131
2354
|
/**
|
|
2132
2355
|
* Optional: để component override riêng.
|
|
2133
2356
|
*/
|
|
@@ -2156,22 +2379,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
2156
2379
|
args: [{ required: false }]
|
|
2157
2380
|
}] } });
|
|
2158
2381
|
|
|
2159
|
-
const ZORRO_MODULES$
|
|
2382
|
+
const ZORRO_MODULES$a = [NzDatePickerModule, NzInputModule];
|
|
2160
2383
|
class DatePickerComponent extends BaseValueAccessor {
|
|
2161
2384
|
constructor() {
|
|
2162
2385
|
super();
|
|
2163
|
-
this.
|
|
2386
|
+
this.field = computed(() => {
|
|
2164
2387
|
const base = this.fieldInput();
|
|
2165
2388
|
if (!(base instanceof DatePickerField) ||
|
|
2166
|
-
(base.type !== FieldTypeEnum.DatePicker &&
|
|
2167
|
-
|
|
2389
|
+
(base.type !== FieldTypeEnum.DatePicker &&
|
|
2390
|
+
base.controlType !== ControlTypeEnum.Date)) {
|
|
2391
|
+
throw new Error("Expected DatePickerField");
|
|
2168
2392
|
}
|
|
2169
2393
|
return base;
|
|
2170
2394
|
});
|
|
2171
|
-
|
|
2395
|
+
// Định dạng ngày
|
|
2396
|
+
this.format = computed(() => {
|
|
2397
|
+
return this.field().format ?? "dd-MM-yyyy";
|
|
2398
|
+
});
|
|
2172
2399
|
// Kiểm tra có cho phép chọn ngày quá khứ hay ngày tương lai hay không?
|
|
2173
2400
|
this.disabledDate = computed(() => {
|
|
2174
|
-
const field = this.
|
|
2401
|
+
const field = this.field();
|
|
2175
2402
|
return (current) => {
|
|
2176
2403
|
if (field.disabledDateFn) {
|
|
2177
2404
|
return field.disabledDateFn(current);
|
|
@@ -2186,52 +2413,44 @@ class DatePickerComponent extends BaseValueAccessor {
|
|
|
2186
2413
|
return false;
|
|
2187
2414
|
};
|
|
2188
2415
|
});
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
if (this.
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
}
|
|
2197
|
-
});
|
|
2198
|
-
// Trigger reset từ bên ngoài form.
|
|
2199
|
-
effect(() => {
|
|
2200
|
-
const reset = this.dFormService.resetTrigger();
|
|
2201
|
-
if (reset?.formId === this.formId) {
|
|
2202
|
-
this.reset();
|
|
2203
|
-
}
|
|
2416
|
+
this.viewDisplayValue = computed(() => {
|
|
2417
|
+
// 1. Nếu không phải View thì không cần quan tâm text này
|
|
2418
|
+
if (!this.isView())
|
|
2419
|
+
return "";
|
|
2420
|
+
// 2. Lấy giá trị từ valueSignal
|
|
2421
|
+
const val = this.valueSignal();
|
|
2422
|
+
return val ? FormUtils.convertViewDate(val, this.format()) : NO_INFO_TEXT;
|
|
2204
2423
|
});
|
|
2205
2424
|
}
|
|
2425
|
+
// Xử lý tạo placeholder text tự động nếu chưa truyền placeholder vào config của field
|
|
2426
|
+
resolvePlaceholderText() {
|
|
2427
|
+
return createDatePickerPlaceholder(this.field());
|
|
2428
|
+
}
|
|
2429
|
+
// Sự kiện khi người dùng chọn ngày
|
|
2206
2430
|
handleChangeDate(date) {
|
|
2207
2431
|
this.propagateValue(date);
|
|
2208
2432
|
}
|
|
2209
|
-
// Chạy khi value form được gán bởi các hàm reset, patchValue, setValue
|
|
2433
|
+
// Chạy khi value form được gán bởi các hàm reset, patchValue, setValue
|
|
2210
2434
|
writeValueToView(value) {
|
|
2211
|
-
if (this.isView()) {
|
|
2212
|
-
this.displayValue = value
|
|
2213
|
-
? FormUtils.convertViewDate(value, this.fieldSignal().format ?? 'dd-MM-yyyy')
|
|
2214
|
-
: NO_INFO_TEXT;
|
|
2215
|
-
return;
|
|
2216
|
-
}
|
|
2217
2435
|
if (!this.isAddOrEdit())
|
|
2218
2436
|
return;
|
|
2219
|
-
const { outputAs } =
|
|
2220
|
-
this.fieldService.updateDependValuesMap(this.fieldKey(), value ? formatDateToYYYYMMDD(value) :
|
|
2221
|
-
// Gán data vào đầu ra của form
|
|
2437
|
+
const { outputAs } = this.field();
|
|
2438
|
+
this.fieldService.updateDependValuesMap(this.fieldKey(), value ? formatDateToYYYYMMDD(value) : "");
|
|
2439
|
+
// Gán data vào đầu ra của form
|
|
2222
2440
|
const newOutputValue = value && this.getValueByOutputAs(value, outputAs);
|
|
2223
2441
|
this.patchFormData(this.fieldKey(), newOutputValue);
|
|
2224
2442
|
}
|
|
2225
2443
|
// Xử lý phụ thuộc khi change value
|
|
2226
2444
|
handleValueChange(value) {
|
|
2227
|
-
const { outputAs, isParent } =
|
|
2445
|
+
const { outputAs, isParent } = this.field();
|
|
2228
2446
|
if (isParent) {
|
|
2229
|
-
this.fieldService.updateDependValuesMap(this.fieldKey(), value ? formatDateToYYYYMMDD(value) :
|
|
2447
|
+
this.fieldService.updateDependValuesMap(this.fieldKey(), value ? formatDateToYYYYMMDD(value) : "");
|
|
2230
2448
|
}
|
|
2231
|
-
// Gán data vào đầu ra của form
|
|
2449
|
+
// Gán data vào đầu ra của form
|
|
2232
2450
|
const newOutputValue = value && this.getValueByOutputAs(value, outputAs);
|
|
2233
2451
|
this.patchFormData(this.fieldKey(), newOutputValue);
|
|
2234
2452
|
}
|
|
2453
|
+
// Biến đổi giá trị đầu ra theo outputAs
|
|
2235
2454
|
getValueByOutputAs(date, outputAs) {
|
|
2236
2455
|
let value = date;
|
|
2237
2456
|
if (outputAs === DatePickerOutputValueTypeEnum.String) {
|
|
@@ -2246,35 +2465,44 @@ class DatePickerComponent extends BaseValueAccessor {
|
|
|
2246
2465
|
useExisting: forwardRef(() => DatePickerComponent),
|
|
2247
2466
|
multi: true,
|
|
2248
2467
|
},
|
|
2249
|
-
], usesInheritance: true, ngImport: i0, template: "@if (modeSignal() === formModeEnum.View) {\r\n <input
|
|
2468
|
+
], usesInheritance: true, ngImport: i0, template: "@if (modeSignal() === formModeEnum.View) {\r\n <input\r\n nz-input\r\n [value]=\"viewDisplayValue()\"\r\n [disabled]=\"true\"\r\n class=\"modeView\"\r\n />\r\n} @else {\r\n <nz-date-picker\r\n [id]=\"fieldKey()\"\r\n [class]=\"'w-100'\"\r\n [nzDisabled]=\"disabledSignal()\"\r\n [nzPlaceHolder]=\"displayPlaceholder()\"\r\n [nzFormat]=\"format()\"\r\n [nzDisabledDate]=\"disabledDate()\"\r\n [ngModel]=\"valueSignal()\"\r\n (ngModelChange)=\"handleChangeDate($event)\"\r\n >\r\n </nz-date-picker>\r\n}\r\n", styles: [":host ::ng-deep .ant-input[disabled]{background-color:#fff}\n"], dependencies: [{ kind: "ngmodule", type: i1.FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i2.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzAllowClear", "nzAutoFocus", "nzDisabled", "nzBorderless", "nzInputReadOnly", "nzInline", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i1$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }] }); }
|
|
2250
2469
|
}
|
|
2251
2470
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DatePickerComponent, decorators: [{
|
|
2252
2471
|
type: Component,
|
|
2253
|
-
args: [{ selector:
|
|
2472
|
+
args: [{ selector: "app-date-picker", standalone: true, imports: [...FORM_MODULES, ...ZORRO_MODULES$a], providers: [
|
|
2254
2473
|
{
|
|
2255
2474
|
provide: NG_VALUE_ACCESSOR,
|
|
2256
2475
|
useExisting: forwardRef(() => DatePickerComponent),
|
|
2257
2476
|
multi: true,
|
|
2258
2477
|
},
|
|
2259
|
-
], template: "@if (modeSignal() === formModeEnum.View) {\r\n <input
|
|
2478
|
+
], template: "@if (modeSignal() === formModeEnum.View) {\r\n <input\r\n nz-input\r\n [value]=\"viewDisplayValue()\"\r\n [disabled]=\"true\"\r\n class=\"modeView\"\r\n />\r\n} @else {\r\n <nz-date-picker\r\n [id]=\"fieldKey()\"\r\n [class]=\"'w-100'\"\r\n [nzDisabled]=\"disabledSignal()\"\r\n [nzPlaceHolder]=\"displayPlaceholder()\"\r\n [nzFormat]=\"format()\"\r\n [nzDisabledDate]=\"disabledDate()\"\r\n [ngModel]=\"valueSignal()\"\r\n (ngModelChange)=\"handleChangeDate($event)\"\r\n >\r\n </nz-date-picker>\r\n}\r\n", styles: [":host ::ng-deep .ant-input[disabled]{background-color:#fff}\n"] }]
|
|
2260
2479
|
}], ctorParameters: () => [] });
|
|
2261
2480
|
|
|
2262
|
-
const ZORRO_MODULES$
|
|
2481
|
+
const ZORRO_MODULES$9 = [NzDatePickerModule, NzInputModule];
|
|
2263
2482
|
class DateRangeComponent extends BaseValueAccessor {
|
|
2264
2483
|
constructor() {
|
|
2265
2484
|
super();
|
|
2266
|
-
this.
|
|
2485
|
+
this.field = computed(() => {
|
|
2267
2486
|
const base = this.fieldInput();
|
|
2268
2487
|
if (!(base instanceof DateRangeField) ||
|
|
2269
|
-
(base.type !== FieldTypeEnum.DateRange &&
|
|
2270
|
-
|
|
2488
|
+
(base.type !== FieldTypeEnum.DateRange &&
|
|
2489
|
+
base.controlType !== ControlTypeEnum.Date)) {
|
|
2490
|
+
throw new Error("Expected DatePickerField");
|
|
2271
2491
|
}
|
|
2272
2492
|
return base;
|
|
2273
2493
|
});
|
|
2274
|
-
|
|
2494
|
+
// Định dạng ngày
|
|
2495
|
+
this.format = computed(() => {
|
|
2496
|
+
return this.field().format ?? "dd-MM-yyyy";
|
|
2497
|
+
});
|
|
2498
|
+
this.placeholders = computed(() => {
|
|
2499
|
+
return this.field().placeholders ?? ["Ngày bắt đầu", "Ngày kết thúc"];
|
|
2500
|
+
});
|
|
2501
|
+
// Nếu mảng date không lớn hơn 2
|
|
2502
|
+
this.displayValueNoInfo = NO_INFO_TEXT;
|
|
2275
2503
|
// Kiểm tra có cho phép chọn ngày quá khứ hay ngày tương lai hay không?
|
|
2276
2504
|
this.disabledDate = computed(() => {
|
|
2277
|
-
const field = this.
|
|
2505
|
+
const field = this.field();
|
|
2278
2506
|
return (current) => {
|
|
2279
2507
|
const today = new Date();
|
|
2280
2508
|
const diff = differenceInCalendarDays(current, today);
|
|
@@ -2286,44 +2514,21 @@ class DateRangeComponent extends BaseValueAccessor {
|
|
|
2286
2514
|
return false;
|
|
2287
2515
|
};
|
|
2288
2516
|
});
|
|
2289
|
-
// Trigger reset từ bên ngoài form.
|
|
2290
|
-
effect(() => {
|
|
2291
|
-
const reset = this.dFormService.resetTrigger();
|
|
2292
|
-
if (reset?.formId === this.formId) {
|
|
2293
|
-
this.reset();
|
|
2294
|
-
}
|
|
2295
|
-
});
|
|
2296
|
-
}
|
|
2297
|
-
getSelectedDateRangeFromFieldValue(fieldValue) {
|
|
2298
|
-
let dateRange = [];
|
|
2299
|
-
if (fieldValue?.length === 2) {
|
|
2300
|
-
const startDate = normalizeToDate(fieldValue[0]);
|
|
2301
|
-
const endDate = normalizeToDate(fieldValue[1]);
|
|
2302
|
-
if (startDate && endDate)
|
|
2303
|
-
dateRange = [startDate, endDate];
|
|
2304
|
-
}
|
|
2305
|
-
return dateRange;
|
|
2306
2517
|
}
|
|
2307
2518
|
handleChangeDateRange(dateRange) {
|
|
2308
2519
|
this.propagateValue(dateRange);
|
|
2309
2520
|
}
|
|
2310
2521
|
// Chạy khi value form được gán bởi các hàm reset, patchValue, setValue.
|
|
2311
2522
|
writeValueToView(value) {
|
|
2312
|
-
if (this.isView()) {
|
|
2313
|
-
if (value.length === 0) {
|
|
2314
|
-
this.displayValueNoInfo = NO_INFO_TEXT;
|
|
2315
|
-
return;
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2318
2523
|
if (!this.isAddOrEdit())
|
|
2319
2524
|
return;
|
|
2320
|
-
const { outputAs } = untracked(() => this.
|
|
2525
|
+
const { outputAs } = untracked(() => this.field());
|
|
2321
2526
|
// Gán data vào đầu ra của form.
|
|
2322
2527
|
this.patchFormData(this.fieldKey(), value.length > 0 ? this.getValueByOutputAs(value, outputAs) : null);
|
|
2323
2528
|
}
|
|
2324
2529
|
// Xử lý phụ thuộc khi change value
|
|
2325
2530
|
handleValueChange(value) {
|
|
2326
|
-
const { outputAs } = untracked(() => this.
|
|
2531
|
+
const { outputAs } = untracked(() => this.field());
|
|
2327
2532
|
// Gán data vào đầu ra của form.
|
|
2328
2533
|
this.patchFormData(this.fieldKey(), value.length > 0 ? this.getValueByOutputAs(value, outputAs) : null);
|
|
2329
2534
|
}
|
|
@@ -2335,7 +2540,10 @@ class DateRangeComponent extends BaseValueAccessor {
|
|
|
2335
2540
|
value = `${formatDateToYYYYMMDD(dateRange[0])},${formatDateToYYYYMMDD(dateRange[1])}`;
|
|
2336
2541
|
}
|
|
2337
2542
|
if (outputAs === DateRangeOutputValueTypeEnum.StringArray) {
|
|
2338
|
-
value = [
|
|
2543
|
+
value = [
|
|
2544
|
+
formatDateToYYYYMMDD(dateRange[0]),
|
|
2545
|
+
formatDateToYYYYMMDD(dateRange[1]),
|
|
2546
|
+
];
|
|
2339
2547
|
}
|
|
2340
2548
|
}
|
|
2341
2549
|
return value;
|
|
@@ -2347,72 +2555,17 @@ class DateRangeComponent extends BaseValueAccessor {
|
|
|
2347
2555
|
useExisting: forwardRef(() => DateRangeComponent),
|
|
2348
2556
|
multi: true,
|
|
2349
2557
|
},
|
|
2350
|
-
], usesInheritance: true, ngImport: i0, template: "@if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
2558
|
+
], usesInheritance: true, ngImport: i0, template: "@if (modeSignal() === formModeEnum.View) {\r\n @if (valueSignal()!.length > 0) {\r\n <nz-range-picker\r\n [class]=\"'w-100'\"\r\n [nzFormat]=\"format()\"\r\n [nzDisabled]=\"true\"\r\n [ngModel]=\"valueSignal()\"\r\n class=\"modeView\"\r\n [nzSuffixIcon]=\"suffixIcon\"\r\n ></nz-range-picker>\r\n <ng-template #suffixIcon>\r\n <!-- \u0110\u1EC3 tr\u1ED1ng, ho\u1EB7c custom icon kh\u00E1c -->\r\n </ng-template>\r\n } @else {\r\n <input\r\n nz-input\r\n [value]=\"displayValueNoInfo\"\r\n [disabled]=\"true\"\r\n class=\"modeView\"\r\n />\r\n }\r\n} @else {\r\n <nz-range-picker\r\n [id]=\"fieldKey()\"\r\n class=\"w-100\"\r\n [nzDisabled]=\"disabledSignal()\"\r\n [nzFormat]=\"format()\"\r\n [nzDisabledDate]=\"disabledDate()\"\r\n [nzPlaceHolder]=\"placeholders()\"\r\n [ngModel]=\"valueSignal()\"\r\n (ngModelChange)=\"handleChangeDateRange($event)\"\r\n ></nz-range-picker>\r\n}\r\n", styles: [":host ::ng-deep .modeView.ant-picker.ant-picker-disabled{background-color:inherit!important;cursor:default;pointer-events:none}:host ::ng-deep .modeView .ant-picker-input>input[disabled]{color:#575757!important}.modeView{pointer-events:none;color:#575757!important}\n"], dependencies: [{ kind: "ngmodule", type: i1.FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i2.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzAllowClear", "nzAutoFocus", "nzDisabled", "nzBorderless", "nzInputReadOnly", "nzInline", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "directive", type: i2.NzRangePickerComponent, selector: "nz-range-picker", exportAs: ["nzRangePicker"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i1$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }] }); }
|
|
2351
2559
|
}
|
|
2352
2560
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DateRangeComponent, decorators: [{
|
|
2353
2561
|
type: Component,
|
|
2354
|
-
args: [{ selector:
|
|
2562
|
+
args: [{ selector: "app-date-range", standalone: true, imports: [...FORM_MODULES, ...ZORRO_MODULES$9], providers: [
|
|
2355
2563
|
{
|
|
2356
2564
|
provide: NG_VALUE_ACCESSOR,
|
|
2357
2565
|
useExisting: forwardRef(() => DateRangeComponent),
|
|
2358
2566
|
multi: true,
|
|
2359
2567
|
},
|
|
2360
|
-
], template: "@if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
2361
|
-
}], ctorParameters: () => [] });
|
|
2362
|
-
|
|
2363
|
-
const ZORRO_MODULES$c = [NzInputModule, NzIconModule];
|
|
2364
|
-
class InputPasswordComponent extends BaseValueAccessor {
|
|
2365
|
-
constructor() {
|
|
2366
|
-
super();
|
|
2367
|
-
this.fieldSignal = computed(() => {
|
|
2368
|
-
const base = this.fieldInput();
|
|
2369
|
-
if (!(base instanceof InputPasswordField) ||
|
|
2370
|
-
(base.type !== FieldTypeEnum.InputPassword && base.controlType !== ControlTypeEnum.Input)) {
|
|
2371
|
-
throw new Error('Expected InputPasswordField');
|
|
2372
|
-
}
|
|
2373
|
-
return base;
|
|
2374
|
-
});
|
|
2375
|
-
this.passwordVisible = false;
|
|
2376
|
-
// 1. Effect chung Add + Edit
|
|
2377
|
-
effect(() => {
|
|
2378
|
-
if (this.isAdd()) {
|
|
2379
|
-
const field = this.fieldSignal();
|
|
2380
|
-
const { placeholder } = field;
|
|
2381
|
-
if (!placeholder)
|
|
2382
|
-
field.placeholder = createPlaceholder(field);
|
|
2383
|
-
}
|
|
2384
|
-
});
|
|
2385
|
-
// Trigger reset từ bên ngoài form.
|
|
2386
|
-
effect(() => {
|
|
2387
|
-
const reset = this.dFormService.resetTrigger();
|
|
2388
|
-
if (reset?.formId === this.formId) {
|
|
2389
|
-
this.reset();
|
|
2390
|
-
}
|
|
2391
|
-
});
|
|
2392
|
-
}
|
|
2393
|
-
handleChangeInputPassword(event) {
|
|
2394
|
-
const inputValue = event.target.value;
|
|
2395
|
-
this.propagateValue(inputValue);
|
|
2396
|
-
this.patchFormData(this.fieldKey(), inputValue);
|
|
2397
|
-
}
|
|
2398
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InputPasswordComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2399
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: InputPasswordComponent, isStandalone: true, selector: "app-input-password", providers: [
|
|
2400
|
-
{
|
|
2401
|
-
provide: NG_VALUE_ACCESSOR,
|
|
2402
|
-
useExisting: forwardRef(() => InputPasswordComponent),
|
|
2403
|
-
multi: true,
|
|
2404
|
-
},
|
|
2405
|
-
], usesInheritance: true, ngImport: i0, template: "<nz-input-group [nzSuffix]=\"suffixTemplate\">\r\n <input\r\n nz-input\r\n [value]=\"value\"\r\n [type]=\"passwordVisible ? 'text' : 'password'\"\r\n autocomplete=\"new-password\"\r\n [placeholder]=\"fieldSignal().placeholder!\"\r\n (input)=\"handleChangeInputPassword($event)\"\r\n (blur)=\"onTouched()\"\r\n />\r\n</nz-input-group>\r\n<ng-template #suffixTemplate>\r\n <span\r\n nz-icon\r\n [nzType]=\"passwordVisible ? 'eye-invisible' : 'eye'\"\r\n (click)=\"passwordVisible = !passwordVisible\"\r\n ></span>\r\n</ng-template>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i1$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "component", type: i1$1.NzInputGroupComponent, selector: "nz-input-group", inputs: ["nzAddOnBeforeIcon", "nzAddOnAfterIcon", "nzPrefixIcon", "nzSuffixIcon", "nzAddOnBefore", "nzAddOnAfter", "nzPrefix", "nzStatus", "nzSuffix", "nzSize", "nzSearch", "nzCompact"], exportAs: ["nzInputGroup"] }, { kind: "directive", type: i1$1.NzInputGroupWhitSuffixOrPrefixDirective, selector: "nz-input-group[nzSuffix], nz-input-group[nzPrefix]" }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }] }); }
|
|
2406
|
-
}
|
|
2407
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InputPasswordComponent, decorators: [{
|
|
2408
|
-
type: Component,
|
|
2409
|
-
args: [{ selector: 'app-input-password', standalone: true, imports: [...ZORRO_MODULES$c], providers: [
|
|
2410
|
-
{
|
|
2411
|
-
provide: NG_VALUE_ACCESSOR,
|
|
2412
|
-
useExisting: forwardRef(() => InputPasswordComponent),
|
|
2413
|
-
multi: true,
|
|
2414
|
-
},
|
|
2415
|
-
], template: "<nz-input-group [nzSuffix]=\"suffixTemplate\">\r\n <input\r\n nz-input\r\n [value]=\"value\"\r\n [type]=\"passwordVisible ? 'text' : 'password'\"\r\n autocomplete=\"new-password\"\r\n [placeholder]=\"fieldSignal().placeholder!\"\r\n (input)=\"handleChangeInputPassword($event)\"\r\n (blur)=\"onTouched()\"\r\n />\r\n</nz-input-group>\r\n<ng-template #suffixTemplate>\r\n <span\r\n nz-icon\r\n [nzType]=\"passwordVisible ? 'eye-invisible' : 'eye'\"\r\n (click)=\"passwordVisible = !passwordVisible\"\r\n ></span>\r\n</ng-template>\r\n" }]
|
|
2568
|
+
], template: "@if (modeSignal() === formModeEnum.View) {\r\n @if (valueSignal()!.length > 0) {\r\n <nz-range-picker\r\n [class]=\"'w-100'\"\r\n [nzFormat]=\"format()\"\r\n [nzDisabled]=\"true\"\r\n [ngModel]=\"valueSignal()\"\r\n class=\"modeView\"\r\n [nzSuffixIcon]=\"suffixIcon\"\r\n ></nz-range-picker>\r\n <ng-template #suffixIcon>\r\n <!-- \u0110\u1EC3 tr\u1ED1ng, ho\u1EB7c custom icon kh\u00E1c -->\r\n </ng-template>\r\n } @else {\r\n <input\r\n nz-input\r\n [value]=\"displayValueNoInfo\"\r\n [disabled]=\"true\"\r\n class=\"modeView\"\r\n />\r\n }\r\n} @else {\r\n <nz-range-picker\r\n [id]=\"fieldKey()\"\r\n class=\"w-100\"\r\n [nzDisabled]=\"disabledSignal()\"\r\n [nzFormat]=\"format()\"\r\n [nzDisabledDate]=\"disabledDate()\"\r\n [nzPlaceHolder]=\"placeholders()\"\r\n [ngModel]=\"valueSignal()\"\r\n (ngModelChange)=\"handleChangeDateRange($event)\"\r\n ></nz-range-picker>\r\n}\r\n", styles: [":host ::ng-deep .modeView.ant-picker.ant-picker-disabled{background-color:inherit!important;cursor:default;pointer-events:none}:host ::ng-deep .modeView .ant-picker-input>input[disabled]{color:#575757!important}.modeView{pointer-events:none;color:#575757!important}\n"] }]
|
|
2416
2569
|
}], ctorParameters: () => [] });
|
|
2417
2570
|
|
|
2418
2571
|
class SuffixService {
|
|
@@ -2433,7 +2586,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
2433
2586
|
}]
|
|
2434
2587
|
}], ctorParameters: () => [] });
|
|
2435
2588
|
|
|
2436
|
-
const ZORRO_MODULES$
|
|
2589
|
+
const ZORRO_MODULES$8 = [NzButtonModule, NzIconModule];
|
|
2437
2590
|
class SuffixComponent {
|
|
2438
2591
|
constructor() {
|
|
2439
2592
|
this.formId = '';
|
|
@@ -2447,73 +2600,215 @@ class SuffixComponent {
|
|
|
2447
2600
|
this.suffixService.onSuffixClick(this.suffixConfig.key, this.formId);
|
|
2448
2601
|
}
|
|
2449
2602
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: SuffixComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2450
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: SuffixComponent, isStandalone: true, selector: "app-suffix", inputs: { suffixConfig: "suffixConfig", formId: "formId" }, ngImport: i0, template: "<button\r\n nz-button\r\n nzType=\"primary\"\r\n nzSize=\"small\"\r\n [title]=\"suffixConfig.description\"\r\n class=\"h-100 suffix-btn font-size-12\"\r\n [ngClass]=\"suffixConfig.class ?? ''\"\r\n (click)=\"handleSuffix()\"\r\n>\r\n @if (suffixConfig.icon) {\r\n <span class=\"icon\">\r\n <!-- N\u1EBFu l\u00E0 icon Zorro -->\r\n @if (suffixConfig.icon.type === 'zorro') {\r\n <span\r\n nz-icon\r\n [nzType]=\"suffixConfig.icon.value\"\r\n nzTheme=\"outline\"\r\n [ngClass]=\"suffixConfig.icon.class ?? ''\"\r\n >\r\n </span>\r\n }\r\n\r\n <!-- N\u1EBFu l\u00E0 Boxicons -->\r\n @if (suffixConfig.icon.type === 'mdi') {\r\n <span [class]=\"'mdi ' + suffixConfig.icon.value\" [ngClass]=\"suffixConfig.icon.class ?? ''\">\r\n </span>\r\n }\r\n </span>\r\n }\r\n\r\n @if (suffixConfig.label) {\r\n <span class=\"label\">\r\n {{ suffixConfig.label }}\r\n </span>\r\n }\r\n\r\n @if (!suffixConfig.icon && !suffixConfig.label) {\r\n <span class=\"label\">\r\n {{ defaultText }}\r\n </span>\r\n }\r\n</button>\r\n", styles: [".
|
|
2603
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: SuffixComponent, isStandalone: true, selector: "app-suffix", inputs: { suffixConfig: "suffixConfig", formId: "formId" }, ngImport: i0, template: "<button\r\n nz-button\r\n nzType=\"primary\"\r\n nzSize=\"small\"\r\n [title]=\"suffixConfig.description\"\r\n class=\"h-100 suffix-btn font-size-12\"\r\n [ngClass]=\"suffixConfig.class ?? ''\"\r\n (click)=\"handleSuffix()\"\r\n>\r\n @if (suffixConfig.icon) {\r\n <span class=\"icon\">\r\n <!-- N\u1EBFu l\u00E0 icon Zorro -->\r\n @if (suffixConfig.icon.type === 'zorro') {\r\n <span\r\n nz-icon\r\n [nzType]=\"suffixConfig.icon.value\"\r\n nzTheme=\"outline\"\r\n [ngClass]=\"suffixConfig.icon.class ?? ''\"\r\n >\r\n </span>\r\n }\r\n\r\n <!-- N\u1EBFu l\u00E0 Boxicons -->\r\n @if (suffixConfig.icon.type === 'mdi') {\r\n <span [class]=\"'mdi ' + suffixConfig.icon.value\" [ngClass]=\"suffixConfig.icon.class ?? ''\">\r\n </span>\r\n }\r\n </span>\r\n }\r\n\r\n @if (suffixConfig.label) {\r\n <span class=\"label\">\r\n {{ suffixConfig.label }}\r\n </span>\r\n }\r\n\r\n @if (!suffixConfig.icon && !suffixConfig.label) {\r\n <span class=\"label\">\r\n {{ defaultText }}\r\n </span>\r\n }\r\n</button>\r\n", styles: [".suffix-btn{margin-left:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: i1$2.CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i4.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i5.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i6.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }] }); }
|
|
2451
2604
|
}
|
|
2452
2605
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: SuffixComponent, decorators: [{
|
|
2453
2606
|
type: Component,
|
|
2454
|
-
args: [{ selector: 'app-suffix', standalone: true, imports: [...CORE_MODULES, ...ZORRO_MODULES$
|
|
2607
|
+
args: [{ selector: 'app-suffix', standalone: true, imports: [...CORE_MODULES, ...ZORRO_MODULES$8], template: "<button\r\n nz-button\r\n nzType=\"primary\"\r\n nzSize=\"small\"\r\n [title]=\"suffixConfig.description\"\r\n class=\"h-100 suffix-btn font-size-12\"\r\n [ngClass]=\"suffixConfig.class ?? ''\"\r\n (click)=\"handleSuffix()\"\r\n>\r\n @if (suffixConfig.icon) {\r\n <span class=\"icon\">\r\n <!-- N\u1EBFu l\u00E0 icon Zorro -->\r\n @if (suffixConfig.icon.type === 'zorro') {\r\n <span\r\n nz-icon\r\n [nzType]=\"suffixConfig.icon.value\"\r\n nzTheme=\"outline\"\r\n [ngClass]=\"suffixConfig.icon.class ?? ''\"\r\n >\r\n </span>\r\n }\r\n\r\n <!-- N\u1EBFu l\u00E0 Boxicons -->\r\n @if (suffixConfig.icon.type === 'mdi') {\r\n <span [class]=\"'mdi ' + suffixConfig.icon.value\" [ngClass]=\"suffixConfig.icon.class ?? ''\">\r\n </span>\r\n }\r\n </span>\r\n }\r\n\r\n @if (suffixConfig.label) {\r\n <span class=\"label\">\r\n {{ suffixConfig.label }}\r\n </span>\r\n }\r\n\r\n @if (!suffixConfig.icon && !suffixConfig.label) {\r\n <span class=\"label\">\r\n {{ defaultText }}\r\n </span>\r\n }\r\n</button>\r\n", styles: [".suffix-btn{margin-left:.5rem}\n"] }]
|
|
2455
2608
|
}], propDecorators: { suffixConfig: [{
|
|
2456
2609
|
type: Input
|
|
2457
2610
|
}], formId: [{
|
|
2458
2611
|
type: Input
|
|
2459
2612
|
}] } });
|
|
2460
2613
|
|
|
2461
|
-
|
|
2614
|
+
class AutoNumericOptionsFactory {
|
|
2615
|
+
static create(field) {
|
|
2616
|
+
if (field.format === NumericPreset.Manual) {
|
|
2617
|
+
return field.autoNumericOptions ?? NUMERIC_PRESETS.integer;
|
|
2618
|
+
}
|
|
2619
|
+
return NUMERIC_PRESETS[field.format];
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
const zorroModules$4 = [NzInputModule];
|
|
2624
|
+
class InputFormattedComponent extends BaseValueAccessor {
|
|
2625
|
+
constructor() {
|
|
2626
|
+
super();
|
|
2627
|
+
this.field = computed(() => {
|
|
2628
|
+
const base = this.fieldInput();
|
|
2629
|
+
if (!(base instanceof InputFormattedField) ||
|
|
2630
|
+
(base.type !== FieldTypeEnum.InputFormatted &&
|
|
2631
|
+
base.controlType !== ControlTypeEnum.Input)) {
|
|
2632
|
+
throw new Error("Expected InputFormattedField");
|
|
2633
|
+
}
|
|
2634
|
+
return base;
|
|
2635
|
+
});
|
|
2636
|
+
this.inputFormattedEle = viewChild("inputFormatted");
|
|
2637
|
+
this.autoNumericOptions = computed(() => AutoNumericOptionsFactory.create(this.field()));
|
|
2638
|
+
this.internalValue = signal("");
|
|
2639
|
+
this.inputDisplayValues = computed(() => {
|
|
2640
|
+
const isView = this.isView();
|
|
2641
|
+
const autoNumericOptions = this.autoNumericOptions();
|
|
2642
|
+
const value = this.internalValue();
|
|
2643
|
+
if (isView) {
|
|
2644
|
+
const viewValue = value
|
|
2645
|
+
? AutoNumeric.format(value, autoNumericOptions)
|
|
2646
|
+
: undefined;
|
|
2647
|
+
return viewValue || NO_INFO_TEXT;
|
|
2648
|
+
}
|
|
2649
|
+
return "";
|
|
2650
|
+
});
|
|
2651
|
+
this.autoNumericLifeCycleEffect = effect((onCleanup) => {
|
|
2652
|
+
const nativeEle = this.inputFormattedEle()?.nativeElement;
|
|
2653
|
+
const isAddOrEdit = this.isAddOrEdit();
|
|
2654
|
+
const autoNumericOptions = untracked(() => this.autoNumericOptions());
|
|
2655
|
+
const value = untracked(() => this.valueSignal());
|
|
2656
|
+
// 1. TẠO BIẾN CỤC BỘ Ở ĐÂY (Đây là mấu chốt)
|
|
2657
|
+
let localAutoNumeric;
|
|
2658
|
+
if (nativeEle && isAddOrEdit) {
|
|
2659
|
+
// 2. Gán vào biến cục bộ
|
|
2660
|
+
localAutoNumeric = new AutoNumeric(nativeEle, value, autoNumericOptions);
|
|
2661
|
+
// 3. Vẫn cập nhật biến class để xài ở chỗ khác
|
|
2662
|
+
this.autoNumeric = localAutoNumeric;
|
|
2663
|
+
}
|
|
2664
|
+
onCleanup(() => {
|
|
2665
|
+
// 4. CHỈ REMOVE BIẾN CỤC BỘ (Không dùng this.autoNumeric ở đây)
|
|
2666
|
+
if (localAutoNumeric) {
|
|
2667
|
+
localAutoNumeric?.remove();
|
|
2668
|
+
// Dọn dẹp biến class nếu nó đang giữ cái vừa bị remove
|
|
2669
|
+
if (this.autoNumeric === localAutoNumeric) {
|
|
2670
|
+
this.autoNumeric = undefined;
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
});
|
|
2674
|
+
});
|
|
2675
|
+
}
|
|
2676
|
+
// Xử lý tạo placeholder text tự động nếu chưa truyền placeholder vào config của field
|
|
2677
|
+
resolvePlaceholderText() {
|
|
2678
|
+
const isDisabled = this.field().isDisabled;
|
|
2679
|
+
return isDisabled ? NO_INFO_TEXT : createInputPlaceholder(this.field());
|
|
2680
|
+
}
|
|
2681
|
+
// event: Event;
|
|
2682
|
+
handleChangeInputText() {
|
|
2683
|
+
const { key } = this.field();
|
|
2684
|
+
// const inputValue = (event.target as HTMLInputElement).value;
|
|
2685
|
+
// Lấy giá trị RAW chuẩn từ AutoNumeric (không lấy event.target.value nữa)
|
|
2686
|
+
// Dùng fallback string rỗng nếu chưa có
|
|
2687
|
+
const rawNumericValue = this.autoNumeric?.getNumericString() || "";
|
|
2688
|
+
this.propagateValue(rawNumericValue);
|
|
2689
|
+
// Gán data vào đầu ra của form.
|
|
2690
|
+
this.patchFormData(key, rawNumericValue.trim());
|
|
2691
|
+
}
|
|
2692
|
+
// Chỗ này vẫn xử lý bình thường cho CVA không liên quan đến AutoNumeric.
|
|
2693
|
+
writeValueToView(value) {
|
|
2694
|
+
// 2. NẾU AutoNumeric ĐÃ ĐƯỢC TẠO (đang ở nhánh Add/Edit), thì ép nó format lại giá trị mới
|
|
2695
|
+
if (this.autoNumeric) {
|
|
2696
|
+
this.autoNumeric.set(value);
|
|
2697
|
+
}
|
|
2698
|
+
const { key } = untracked(() => this.field());
|
|
2699
|
+
// Gán data vào đầu ra của form.
|
|
2700
|
+
this.patchFormData(key, value);
|
|
2701
|
+
}
|
|
2702
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InputFormattedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2703
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: InputFormattedComponent, isStandalone: true, selector: "app-input-formatted", providers: [
|
|
2704
|
+
{
|
|
2705
|
+
provide: NG_VALUE_ACCESSOR,
|
|
2706
|
+
useExisting: forwardRef(() => InputFormattedComponent),
|
|
2707
|
+
multi: true,
|
|
2708
|
+
},
|
|
2709
|
+
], viewQueries: [{ propertyName: "inputFormattedEle", first: true, predicate: ["inputFormatted"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n <input nz-input [value]=\"inputDisplayValues()\" class=\"modeView\" />\r\n }\r\n @if (viewMode() === viewModeEnum.text) {\r\n <span class=\"modeView\">{{ inputDisplayValues() }}</span>\r\n }\r\n } @else {\r\n <!-- [value]=\"value\" -->\r\n\r\n <input\r\n #inputFormatted\r\n nz-input\r\n class=\"input-control custom-input\"\r\n [placeholder]=\"displayPlaceholder()\"\r\n [disabled]=\"isDisabled\"\r\n (input)=\"handleChangeInputText()\"\r\n (blur)=\"onTouched()\"\r\n />\r\n }\r\n\r\n <!-- Suffixes -->\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n", styles: [".input-text-wrapper{display:flex}\n"], dependencies: [{ kind: "ngmodule", type: i1$2.CommonModule }, { kind: "ngmodule", type: i1.FormsModule }, { kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i1$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "component", type: SuffixComponent, selector: "app-suffix", inputs: ["suffixConfig", "formId"] }] }); }
|
|
2710
|
+
}
|
|
2711
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InputFormattedComponent, decorators: [{
|
|
2712
|
+
type: Component,
|
|
2713
|
+
args: [{ selector: "app-input-formatted", standalone: true, imports: [...CORE_MODULES, ...FORM_MODULES, ...zorroModules$4, SuffixComponent], providers: [
|
|
2714
|
+
{
|
|
2715
|
+
provide: NG_VALUE_ACCESSOR,
|
|
2716
|
+
useExisting: forwardRef(() => InputFormattedComponent),
|
|
2717
|
+
multi: true,
|
|
2718
|
+
},
|
|
2719
|
+
], template: "<div class=\"flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n <input nz-input [value]=\"inputDisplayValues()\" class=\"modeView\" />\r\n }\r\n @if (viewMode() === viewModeEnum.text) {\r\n <span class=\"modeView\">{{ inputDisplayValues() }}</span>\r\n }\r\n } @else {\r\n <!-- [value]=\"value\" -->\r\n\r\n <input\r\n #inputFormatted\r\n nz-input\r\n class=\"input-control custom-input\"\r\n [placeholder]=\"displayPlaceholder()\"\r\n [disabled]=\"isDisabled\"\r\n (input)=\"handleChangeInputText()\"\r\n (blur)=\"onTouched()\"\r\n />\r\n }\r\n\r\n <!-- Suffixes -->\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n", styles: [".input-text-wrapper{display:flex}\n"] }]
|
|
2720
|
+
}], ctorParameters: () => [] });
|
|
2721
|
+
|
|
2722
|
+
const ZORRO_MODULES$7 = [NzInputModule, NzIconModule];
|
|
2723
|
+
class InputPasswordComponent extends BaseValueAccessor {
|
|
2724
|
+
constructor() {
|
|
2725
|
+
super();
|
|
2726
|
+
this.field = computed(() => {
|
|
2727
|
+
const base = this.fieldInput();
|
|
2728
|
+
if (!(base instanceof InputPasswordField) ||
|
|
2729
|
+
(base.type !== FieldTypeEnum.InputPassword &&
|
|
2730
|
+
base.controlType !== ControlTypeEnum.Input)) {
|
|
2731
|
+
throw new Error("Expected InputPasswordField");
|
|
2732
|
+
}
|
|
2733
|
+
return base;
|
|
2734
|
+
});
|
|
2735
|
+
this.passwordVisible = false;
|
|
2736
|
+
}
|
|
2737
|
+
// Xử lý tạo placeholder text tự động nếu chưa truyền placeholder vào config của field
|
|
2738
|
+
resolvePlaceholderText() {
|
|
2739
|
+
return createInputPlaceholder(this.field());
|
|
2740
|
+
}
|
|
2741
|
+
handleChangeInputPassword(event) {
|
|
2742
|
+
const inputValue = event.target.value;
|
|
2743
|
+
this.propagateValue(inputValue);
|
|
2744
|
+
this.patchFormData(this.fieldKey(), inputValue);
|
|
2745
|
+
}
|
|
2746
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InputPasswordComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2747
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: InputPasswordComponent, isStandalone: true, selector: "app-input-password", providers: [
|
|
2748
|
+
{
|
|
2749
|
+
provide: NG_VALUE_ACCESSOR,
|
|
2750
|
+
useExisting: forwardRef(() => InputPasswordComponent),
|
|
2751
|
+
multi: true,
|
|
2752
|
+
},
|
|
2753
|
+
], usesInheritance: true, ngImport: i0, template: "<nz-input-group [nzSuffix]=\"suffixTemplate\">\r\n <input\r\n nz-input\r\n [value]=\"value\"\r\n [type]=\"passwordVisible ? 'text' : 'password'\"\r\n autocomplete=\"new-password\"\r\n [placeholder]=\"displayPlaceholder()\"\r\n (input)=\"handleChangeInputPassword($event)\"\r\n (blur)=\"onTouched()\"\r\n />\r\n</nz-input-group>\r\n<ng-template #suffixTemplate>\r\n <span\r\n nz-icon\r\n [nzType]=\"passwordVisible ? 'eye-invisible' : 'eye'\"\r\n (click)=\"passwordVisible = !passwordVisible\"\r\n ></span>\r\n</ng-template>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i1$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "component", type: i1$1.NzInputGroupComponent, selector: "nz-input-group", inputs: ["nzAddOnBeforeIcon", "nzAddOnAfterIcon", "nzPrefixIcon", "nzSuffixIcon", "nzAddOnBefore", "nzAddOnAfter", "nzPrefix", "nzStatus", "nzSuffix", "nzSize", "nzSearch", "nzCompact"], exportAs: ["nzInputGroup"] }, { kind: "directive", type: i1$1.NzInputGroupWhitSuffixOrPrefixDirective, selector: "nz-input-group[nzSuffix], nz-input-group[nzPrefix]" }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }] }); }
|
|
2754
|
+
}
|
|
2755
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InputPasswordComponent, decorators: [{
|
|
2756
|
+
type: Component,
|
|
2757
|
+
args: [{ selector: "app-input-password", standalone: true, imports: [...ZORRO_MODULES$7], providers: [
|
|
2758
|
+
{
|
|
2759
|
+
provide: NG_VALUE_ACCESSOR,
|
|
2760
|
+
useExisting: forwardRef(() => InputPasswordComponent),
|
|
2761
|
+
multi: true,
|
|
2762
|
+
},
|
|
2763
|
+
], template: "<nz-input-group [nzSuffix]=\"suffixTemplate\">\r\n <input\r\n nz-input\r\n [value]=\"value\"\r\n [type]=\"passwordVisible ? 'text' : 'password'\"\r\n autocomplete=\"new-password\"\r\n [placeholder]=\"displayPlaceholder()\"\r\n (input)=\"handleChangeInputPassword($event)\"\r\n (blur)=\"onTouched()\"\r\n />\r\n</nz-input-group>\r\n<ng-template #suffixTemplate>\r\n <span\r\n nz-icon\r\n [nzType]=\"passwordVisible ? 'eye-invisible' : 'eye'\"\r\n (click)=\"passwordVisible = !passwordVisible\"\r\n ></span>\r\n</ng-template>\r\n" }]
|
|
2764
|
+
}], ctorParameters: () => [] });
|
|
2765
|
+
|
|
2766
|
+
const ZORRO_MODULES$6 = [
|
|
2462
2767
|
NzInputModule,
|
|
2463
2768
|
NgxCurrencyDirective,
|
|
2464
2769
|
CurrencyPipe,
|
|
2465
2770
|
CommonModule,
|
|
2466
2771
|
FormsModule,
|
|
2467
2772
|
];
|
|
2468
|
-
const COMPONENTS$
|
|
2773
|
+
const COMPONENTS$3 = [SuffixComponent];
|
|
2469
2774
|
class InputTextComponent extends BaseValueAccessor {
|
|
2470
2775
|
constructor() {
|
|
2471
2776
|
super();
|
|
2472
|
-
this.
|
|
2777
|
+
this.field = computed(() => {
|
|
2473
2778
|
const base = this.fieldInput();
|
|
2474
2779
|
if (!(base instanceof InputTextField) ||
|
|
2475
|
-
(base.type !== FieldTypeEnum.InputText &&
|
|
2476
|
-
|
|
2780
|
+
(base.type !== FieldTypeEnum.InputText &&
|
|
2781
|
+
base.controlType !== ControlTypeEnum.Input)) {
|
|
2782
|
+
throw new Error("Expected InputTextField");
|
|
2477
2783
|
}
|
|
2478
2784
|
return base;
|
|
2479
2785
|
});
|
|
2480
|
-
this.
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
if (!placeholder)
|
|
2488
|
-
field.placeholder = createPlaceholder(field);
|
|
2489
|
-
}
|
|
2490
|
-
});
|
|
2491
|
-
// Trigger reset từ bên ngoài form.
|
|
2492
|
-
effect(() => {
|
|
2493
|
-
const reset = this.dFormService.resetTrigger();
|
|
2494
|
-
if (reset?.formId === this.formId) {
|
|
2495
|
-
this.reset();
|
|
2496
|
-
}
|
|
2786
|
+
this.viewDisplayValue = computed(() => {
|
|
2787
|
+
// 1. Nếu không phải View thì không cần quan tâm text này
|
|
2788
|
+
if (!this.isView())
|
|
2789
|
+
return "";
|
|
2790
|
+
// 2. Lấy giá trị từ valueSignal
|
|
2791
|
+
const val = this.valueSignal();
|
|
2792
|
+
return val ? val : NO_INFO_TEXT;
|
|
2497
2793
|
});
|
|
2498
2794
|
}
|
|
2795
|
+
// Xử lý tạo placeholder text tự động nếu chưa truyền placeholder vào config của field
|
|
2796
|
+
resolvePlaceholderText() {
|
|
2797
|
+
return createInputPlaceholder(this.field());
|
|
2798
|
+
}
|
|
2799
|
+
// Xử lý khi nhập giá trị mới vào input
|
|
2499
2800
|
handleChangeInputText(event) {
|
|
2500
2801
|
const inputValue = event.target.value;
|
|
2501
2802
|
this.propagateValue(inputValue);
|
|
2502
2803
|
// Gán data vào đầu ra của form.
|
|
2503
|
-
this.fieldService.onFieldChange(this.fieldKey(), inputValue);
|
|
2504
2804
|
this.patchFormData(this.fieldKey(), inputValue);
|
|
2505
2805
|
}
|
|
2506
2806
|
handleChangeFormValue(value) {
|
|
2507
2807
|
const inputValue = value?.toString();
|
|
2508
2808
|
this.propagateValue(inputValue);
|
|
2509
|
-
this.fieldService.onFieldChange(this.fieldKey(), inputValue);
|
|
2510
2809
|
this.patchFormData(this.fieldKey(), inputValue);
|
|
2511
2810
|
}
|
|
2512
2811
|
writeValueToView(value) {
|
|
2513
|
-
if (this.isView()) {
|
|
2514
|
-
this.inputDisplayValue = this.fieldSignal().modelValue || NO_INFO_TEXT;
|
|
2515
|
-
return;
|
|
2516
|
-
}
|
|
2517
2812
|
if (!this.isAddOrEdit())
|
|
2518
2813
|
return;
|
|
2519
2814
|
// Gán data vào đầu ra của form.
|
|
@@ -2526,181 +2821,228 @@ class InputTextComponent extends BaseValueAccessor {
|
|
|
2526
2821
|
useExisting: forwardRef(() => InputTextComponent),
|
|
2527
2822
|
multi: true,
|
|
2528
2823
|
},
|
|
2529
|
-
], usesInheritance: true, ngImport: i0, template: "<div class=\"flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
2824
|
+
], usesInheritance: true, ngImport: i0, template: "<div class=\"flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (field().viewMode === viewModeEnum.form) {\r\n @if (field().isCurrency) {\r\n <input\r\n nz-input\r\n [ngModel]=\"viewDisplayValue()\"\r\n class=\"modeView\"\r\n [currencyMask]=\"{\r\n prefix: '',\r\n suffix: ' VND',\r\n thousands: ',',\r\n decimal: '.',\r\n precision: 2,\r\n align: 'left',\r\n }\"\r\n />\r\n } @else {\r\n <input nz-input [value]=\"viewDisplayValue()\" class=\"modeView\" />\r\n }\r\n }\r\n @if (field().viewMode === viewModeEnum.text) {\r\n @if (field().isCurrency) {\r\n <span class=\"modeView\">\r\n {{\r\n viewDisplayValue() | currency: \"VND\" : \"symbol\" : \"1.0-0\" : \"vi-VN\"\r\n }}\r\n </span>\r\n } @else {\r\n <span class=\"modeView\">{{ viewDisplayValue() }}</span>\r\n }\r\n }\r\n } @else {\r\n @if (field().isCurrency) {\r\n <input\r\n nz-input\r\n class=\"input-control\"\r\n [currencyMask]=\"{\r\n prefix: '',\r\n suffix: ' VND',\r\n thousands: ',',\r\n decimal: '.',\r\n precision: 2,\r\n align: 'left',\r\n }\"\r\n [(ngModel)]=\"value\"\r\n [placeholder]=\"displayPlaceholder()\"\r\n [disabled]=\"isDisabled\"\r\n (ngModelChange)=\"handleChangeFormValue($event)\"\r\n (blur)=\"onTouched()\"\r\n />\r\n } @else {\r\n <input\r\n nz-input\r\n class=\"input-control\"\r\n [value]=\"value\"\r\n [placeholder]=\"displayPlaceholder()\"\r\n [disabled]=\"isDisabled\"\r\n (input)=\"handleChangeInputText($event)\"\r\n (blur)=\"onTouched()\"\r\n />\r\n }\r\n }\r\n\r\n <!-- Suffixes -->\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\" [formId]=\"formId\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i1$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "directive", type: NgxCurrencyDirective, selector: "input[currencyMask]", inputs: ["currencyMask", "options"] }, { kind: "pipe", type: CurrencyPipe, name: "currency" }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SuffixComponent, selector: "app-suffix", inputs: ["suffixConfig", "formId"] }] }); }
|
|
2530
2825
|
}
|
|
2531
2826
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InputTextComponent, decorators: [{
|
|
2532
2827
|
type: Component,
|
|
2533
|
-
args: [{ selector:
|
|
2828
|
+
args: [{ selector: "app-input-text", standalone: true, imports: [...ZORRO_MODULES$6, ...COMPONENTS$3], providers: [
|
|
2534
2829
|
{
|
|
2535
2830
|
provide: NG_VALUE_ACCESSOR,
|
|
2536
2831
|
useExisting: forwardRef(() => InputTextComponent),
|
|
2537
2832
|
multi: true,
|
|
2538
2833
|
},
|
|
2539
|
-
], template: "<div class=\"flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
2834
|
+
], template: "<div class=\"flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (field().viewMode === viewModeEnum.form) {\r\n @if (field().isCurrency) {\r\n <input\r\n nz-input\r\n [ngModel]=\"viewDisplayValue()\"\r\n class=\"modeView\"\r\n [currencyMask]=\"{\r\n prefix: '',\r\n suffix: ' VND',\r\n thousands: ',',\r\n decimal: '.',\r\n precision: 2,\r\n align: 'left',\r\n }\"\r\n />\r\n } @else {\r\n <input nz-input [value]=\"viewDisplayValue()\" class=\"modeView\" />\r\n }\r\n }\r\n @if (field().viewMode === viewModeEnum.text) {\r\n @if (field().isCurrency) {\r\n <span class=\"modeView\">\r\n {{\r\n viewDisplayValue() | currency: \"VND\" : \"symbol\" : \"1.0-0\" : \"vi-VN\"\r\n }}\r\n </span>\r\n } @else {\r\n <span class=\"modeView\">{{ viewDisplayValue() }}</span>\r\n }\r\n }\r\n } @else {\r\n @if (field().isCurrency) {\r\n <input\r\n nz-input\r\n class=\"input-control\"\r\n [currencyMask]=\"{\r\n prefix: '',\r\n suffix: ' VND',\r\n thousands: ',',\r\n decimal: '.',\r\n precision: 2,\r\n align: 'left',\r\n }\"\r\n [(ngModel)]=\"value\"\r\n [placeholder]=\"displayPlaceholder()\"\r\n [disabled]=\"isDisabled\"\r\n (ngModelChange)=\"handleChangeFormValue($event)\"\r\n (blur)=\"onTouched()\"\r\n />\r\n } @else {\r\n <input\r\n nz-input\r\n class=\"input-control\"\r\n [value]=\"value\"\r\n [placeholder]=\"displayPlaceholder()\"\r\n [disabled]=\"isDisabled\"\r\n (input)=\"handleChangeInputText($event)\"\r\n (blur)=\"onTouched()\"\r\n />\r\n }\r\n }\r\n\r\n <!-- Suffixes -->\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\" [formId]=\"formId\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n" }]
|
|
2540
2835
|
}], ctorParameters: () => [] });
|
|
2541
2836
|
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2837
|
+
class BaseSelectComponent extends BaseValueAccessor {
|
|
2838
|
+
createDependencyStreams(dependsOn) {
|
|
2839
|
+
return dependsOn.map((depend) => this.fieldService
|
|
2840
|
+
.getDependValueChanges$(depend.fieldKey)
|
|
2841
|
+
.pipe(map((val) => ({ key: depend.paramKey, value: val }))));
|
|
2842
|
+
}
|
|
2843
|
+
evaluateDependencies(results, dependType) {
|
|
2844
|
+
const isValidValue = (val) => val !== null && val !== "" && val !== undefined;
|
|
2845
|
+
let isConditionMet = false;
|
|
2846
|
+
if (dependType === DependTypeEnum.Any) {
|
|
2847
|
+
isConditionMet = results.some((r) => isValidValue(r.value));
|
|
2848
|
+
}
|
|
2849
|
+
else {
|
|
2850
|
+
isConditionMet = results.every((r) => isValidValue(r.value));
|
|
2851
|
+
}
|
|
2852
|
+
const params = results.reduce((acc, curr) => ({ ...acc, [curr.key]: curr.value }), {});
|
|
2853
|
+
return { valid: isConditionMet, params };
|
|
2854
|
+
}
|
|
2545
2855
|
constructor() {
|
|
2546
2856
|
super();
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2857
|
+
// Alias to strongly type the field input for Select base logic
|
|
2858
|
+
this.selectField = computed(() => this.fieldInput());
|
|
2859
|
+
this.isFirstLoad = true;
|
|
2860
|
+
// 1. Tạo stream params từ các field phụ thuộc
|
|
2861
|
+
this.dependParams$ = toObservable(this.selectField).pipe(switchMap((field) => {
|
|
2862
|
+
const { dependsOn, dependType } = field;
|
|
2863
|
+
if (!dependsOn || dependsOn.length === 0) {
|
|
2864
|
+
return of({ valid: true, params: {} });
|
|
2552
2865
|
}
|
|
2553
|
-
|
|
2866
|
+
const dependObs$ = this.createDependencyStreams(dependsOn);
|
|
2867
|
+
return combineLatest(dependObs$).pipe(map((results) => this.evaluateDependencies(results, dependType)));
|
|
2868
|
+
}));
|
|
2869
|
+
this.dependParamsSignal = toSignal(this.dependParams$, {
|
|
2870
|
+
initialValue: { valid: false, params: {} },
|
|
2554
2871
|
});
|
|
2555
|
-
|
|
2556
|
-
this.
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2872
|
+
// 2. rxResource lấy danh sách
|
|
2873
|
+
this.optionsResource = rxResource({
|
|
2874
|
+
request: () => {
|
|
2875
|
+
if (this.isView())
|
|
2876
|
+
return undefined;
|
|
2877
|
+
const state = this.dependParamsSignal();
|
|
2878
|
+
if (!state || !state.valid)
|
|
2879
|
+
return undefined;
|
|
2880
|
+
return state.params;
|
|
2881
|
+
},
|
|
2882
|
+
loader: ({ request: params }) => {
|
|
2883
|
+
const field = untracked(() => this.selectField());
|
|
2884
|
+
const fullApiUrl = field?.apiConfig?.baseUrl || "";
|
|
2885
|
+
const apiParams = field?.apiConfig?.params || {};
|
|
2886
|
+
const rawParams = { ...apiParams, ...params };
|
|
2887
|
+
const finalParams = Object.fromEntries(Object.entries(rawParams).filter(([_, val]) => val !== null && val !== undefined && val !== ""));
|
|
2888
|
+
if (!fullApiUrl) {
|
|
2889
|
+
return of({
|
|
2890
|
+
code: 0,
|
|
2891
|
+
message: "Success",
|
|
2892
|
+
data: field?.options ?? [],
|
|
2893
|
+
});
|
|
2894
|
+
}
|
|
2895
|
+
return this.fieldService.getAllOptions(fullApiUrl, finalParams).pipe(catchError((error) => of({ code: -1, message: "Error", data: [] })));
|
|
2896
|
+
},
|
|
2571
2897
|
});
|
|
2572
|
-
//
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2898
|
+
// Gom chung loading từ rxResource và isDisabledSignal
|
|
2899
|
+
this.disabled = computed(() => this.optionsResource.isLoading() || this.disabledSignal());
|
|
2900
|
+
// 3. Xào nấu Options (Prepend, Append, Filter)
|
|
2901
|
+
this.options = computed(() => {
|
|
2902
|
+
const state = this.dependParamsSignal();
|
|
2903
|
+
const isLoading = this.optionsResource.isLoading();
|
|
2904
|
+
const res = this.optionsResource.value();
|
|
2905
|
+
if (!state || !state.valid || isLoading || !res || res.code !== 0) {
|
|
2906
|
+
return [];
|
|
2577
2907
|
}
|
|
2908
|
+
const field = this.selectField();
|
|
2909
|
+
const { optionsToPrepend, optionsToAppend, exceptOptions } = field;
|
|
2910
|
+
const rawData = res.data || [];
|
|
2911
|
+
return [...optionsToPrepend, ...rawData, ...optionsToAppend].filter((opt) => !exceptOptions.some((ex) => ex[field.bindValue] === opt[field.bindValue]));
|
|
2578
2912
|
});
|
|
2579
|
-
//
|
|
2913
|
+
// 4. Effect xử lý toàn bộ logic Form Control (Disable/Enable/Reset)
|
|
2580
2914
|
effect(() => {
|
|
2581
|
-
const
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2915
|
+
const state = this.dependParamsSignal();
|
|
2916
|
+
const isLoading = this.optionsResource.isLoading();
|
|
2917
|
+
const res = this.optionsResource.value();
|
|
2918
|
+
untracked(() => {
|
|
2919
|
+
// CASE 1 & 2: CHƯA ĐỦ ĐIỀU KIỆN HOẶC ĐANG GỌI API -> Disable và Reset
|
|
2920
|
+
if (!state || !state.valid || isLoading) {
|
|
2921
|
+
this.disableControl();
|
|
2922
|
+
if (!this.isFirstLoad) {
|
|
2923
|
+
this.resetControl();
|
|
2924
|
+
}
|
|
2925
|
+
this.isFirstLoad = false;
|
|
2926
|
+
return;
|
|
2927
|
+
}
|
|
2928
|
+
// CASE 3: API ĐÃ LOAD XONG
|
|
2929
|
+
if (res) {
|
|
2930
|
+
if (res.code !== 0) {
|
|
2931
|
+
this.disableAndResetControl();
|
|
2932
|
+
return;
|
|
2933
|
+
}
|
|
2934
|
+
const field = this.selectField();
|
|
2935
|
+
if (!field.isDisabled) {
|
|
2936
|
+
this.enableControl();
|
|
2937
|
+
}
|
|
2938
|
+
// Móc nối cho các class con có nhu cầu đồng bộ data sau khi load API
|
|
2939
|
+
this.onApiOptionsLoaded();
|
|
2940
|
+
}
|
|
2941
|
+
});
|
|
2589
2942
|
});
|
|
2590
2943
|
}
|
|
2591
|
-
//
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2944
|
+
// Cho phép component con overide nếu cần (ví dụ để hydrate sourceObject)
|
|
2945
|
+
onApiOptionsLoaded() { }
|
|
2946
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: BaseSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2947
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.15", type: BaseSelectComponent, isStandalone: true, usesInheritance: true, ngImport: i0 }); }
|
|
2948
|
+
}
|
|
2949
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: BaseSelectComponent, decorators: [{
|
|
2950
|
+
type: Directive
|
|
2951
|
+
}], ctorParameters: () => [] });
|
|
2952
|
+
|
|
2953
|
+
const ZORRO_MODULES$5 = [NzSelectModule, NzInputModule, NzSpinModule];
|
|
2954
|
+
const COMPONENTS$2 = [SuffixComponent];
|
|
2955
|
+
class MultiSelectComponent extends BaseSelectComponent {
|
|
2956
|
+
constructor() {
|
|
2957
|
+
super();
|
|
2958
|
+
this.field = computed(() => {
|
|
2959
|
+
const base = this.fieldInput();
|
|
2960
|
+
if (!(base instanceof MultiSelectField) ||
|
|
2961
|
+
(base.type !== FieldTypeEnum.MultiSelect &&
|
|
2962
|
+
base.controlType !== ControlTypeEnum.Select)) {
|
|
2963
|
+
throw new Error("Expected MultiSelectField");
|
|
2964
|
+
}
|
|
2965
|
+
return base;
|
|
2966
|
+
});
|
|
2967
|
+
this.displayNoValueText = NO_INFO_TEXT;
|
|
2968
|
+
// Biến đổi dữ liệu hiển thị ở chế độ View
|
|
2969
|
+
this.viewDisplayValue = computed(() => {
|
|
2970
|
+
if (!this.isView())
|
|
2971
|
+
return [];
|
|
2972
|
+
console.log("viewDisplayValue", this.field().modelValue || []);
|
|
2973
|
+
return this.getDisplayValue(this.field().modelValue || []);
|
|
2616
2974
|
});
|
|
2617
|
-
// 4. Đếm số paramKey giá trị đã có (không phải falsy).
|
|
2618
|
-
const availableCount = dependValues.filter(v => v.value).length;
|
|
2619
|
-
// 5. Check xem có thể tiếp tục đến gọi list không.
|
|
2620
|
-
// ===== Nếu dependType là 'all' thì canProceed true chỉ khi availableCount = với requiredCount.
|
|
2621
|
-
// ===== Ngược lại dependType là 'any' chỉ cần availableCount > 0.
|
|
2622
|
-
const canProceed = dependType === DependTypeEnum.All ? availableCount === requiredCount : availableCount > 0;
|
|
2623
|
-
return {
|
|
2624
|
-
canProceed,
|
|
2625
|
-
queryParams: Object.fromEntries(dependValues.map(v => [v.paramKey, v.value])),
|
|
2626
|
-
};
|
|
2627
|
-
}
|
|
2628
|
-
createFullApiUrl(field) {
|
|
2629
|
-
let fullApiUrl = field?.apiConfig?.baseUrl || '';
|
|
2630
|
-
const params = field?.apiConfig?.params || {};
|
|
2631
|
-
this.queryParams = {
|
|
2632
|
-
...this.queryParams,
|
|
2633
|
-
...params,
|
|
2634
|
-
};
|
|
2635
|
-
return fullApiUrl;
|
|
2636
2975
|
}
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
this.options = field?.options ?? [];
|
|
2643
|
-
return;
|
|
2976
|
+
onApiOptionsLoaded() {
|
|
2977
|
+
const field = this.field();
|
|
2978
|
+
if (field.outputAs === SelectOutputValueTypeEnum.SourceObject) {
|
|
2979
|
+
const newOutputValue = this.value && this.getValueByOutputAs(this.value);
|
|
2980
|
+
this.patchFormData(this.fieldKey(), newOutputValue);
|
|
2644
2981
|
}
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
.pipe(finalize(() => {
|
|
2650
|
-
this.loading.set(false);
|
|
2651
|
-
this.enableControl();
|
|
2652
|
-
}), this.takeUntilDestroy())
|
|
2653
|
-
.subscribe({
|
|
2654
|
-
next: (res) => {
|
|
2655
|
-
if (res?.code === 0) {
|
|
2656
|
-
this.options = res?.data;
|
|
2657
|
-
}
|
|
2658
|
-
},
|
|
2659
|
-
error: (error) => { },
|
|
2660
|
-
});
|
|
2982
|
+
}
|
|
2983
|
+
// Xử lý tạo placeholder text tự động nếu chưa truyền placeholder vào config của field
|
|
2984
|
+
resolvePlaceholderText() {
|
|
2985
|
+
return createMultiSelectPlaceholder(this.field());
|
|
2661
2986
|
}
|
|
2662
2987
|
handleChangeOptions(optionValue) {
|
|
2663
2988
|
this.propagateValue(optionValue);
|
|
2664
2989
|
}
|
|
2665
2990
|
// Chạy khi value form được gán bởi các hàm reset, patchValue, setValue.
|
|
2666
2991
|
writeValueToView(value) {
|
|
2667
|
-
if (this.isView()) {
|
|
2668
|
-
const modelValue = this.fieldSignal().modelValue;
|
|
2669
|
-
if (modelValue)
|
|
2670
|
-
this.displayOptionsValue = this.getDisplayValue(modelValue);
|
|
2671
|
-
return;
|
|
2672
|
-
}
|
|
2673
2992
|
if (!this.isAddOrEdit())
|
|
2674
2993
|
return;
|
|
2994
|
+
this.fieldService.emitDependValueChange(this.fieldKey(), value.length ? value.join(",") : "");
|
|
2675
2995
|
// Gán data vào đầu ra của form.
|
|
2676
2996
|
const newOutputValue = value && this.getValueByOutputAs(value);
|
|
2677
2997
|
this.patchFormData(this.fieldKey(), newOutputValue);
|
|
2678
2998
|
}
|
|
2679
2999
|
// Xử lý phụ thuộc khi change value
|
|
2680
3000
|
handleValueChange(value) {
|
|
3001
|
+
const { isParent } = this.field();
|
|
3002
|
+
if (isParent) {
|
|
3003
|
+
console.log("cscs");
|
|
3004
|
+
this.fieldService.emitDependValueChange(this.fieldKey(), value.length ? value.join(",") : "");
|
|
3005
|
+
}
|
|
2681
3006
|
const newOutputValue = value && this.getValueByOutputAs(value);
|
|
2682
3007
|
this.patchFormData(this.fieldKey(), newOutputValue);
|
|
2683
3008
|
}
|
|
2684
3009
|
// Xử lý output value đầu ra theo outputAs mà người dùng mong muốn.
|
|
2685
3010
|
getValueByOutputAs(singleValueArr) {
|
|
2686
|
-
const field = this.
|
|
3011
|
+
const field = this.field();
|
|
3012
|
+
const { outputAs, bindValue, modelValue } = field;
|
|
2687
3013
|
if (singleValueArr.length === 0) {
|
|
2688
3014
|
return singleValueArr.map(String);
|
|
2689
3015
|
}
|
|
2690
3016
|
// Nếu outputAs là dạng single.
|
|
2691
3017
|
let value = singleValueArr.map(String);
|
|
2692
3018
|
// Nếu outputAs là dạng object.
|
|
2693
|
-
if (
|
|
2694
|
-
value = value.map(val => ({
|
|
2695
|
-
[
|
|
3019
|
+
if (outputAs === SelectOutputValueTypeEnum.Object) {
|
|
3020
|
+
value = value.map((val) => ({
|
|
3021
|
+
[bindValue]: val,
|
|
2696
3022
|
}));
|
|
2697
3023
|
}
|
|
3024
|
+
// Nếu outputAs là dạng SourceObject.
|
|
3025
|
+
if (outputAs === SelectOutputValueTypeEnum.SourceObject) {
|
|
3026
|
+
const options = untracked(() => this.options());
|
|
3027
|
+
value = singleValueArr.map((val) => {
|
|
3028
|
+
// 1. Tìm trong options hiện tại
|
|
3029
|
+
let foundValue = options.find((opt) => opt[bindValue] === val);
|
|
3030
|
+
// 2. Fallback tìm trong modelValue (vì modelValue có thể là array of objects)
|
|
3031
|
+
// if (!foundValue && modelValue && Array.isArray(modelValue)) {
|
|
3032
|
+
// foundValue = modelValue.find(
|
|
3033
|
+
// (mOpt: any) => typeof mOpt === "object" && mOpt[bindValue] === val
|
|
3034
|
+
// );
|
|
3035
|
+
// }
|
|
3036
|
+
// 3. Fallback cuối cùng
|
|
3037
|
+
return foundValue ?? { [bindValue]: val };
|
|
3038
|
+
});
|
|
3039
|
+
}
|
|
2698
3040
|
return value;
|
|
2699
3041
|
}
|
|
2700
3042
|
// Làm phẳng giá trị để hiện thị ở chế độ View.
|
|
2701
3043
|
getDisplayValue(value) {
|
|
2702
3044
|
const optionsValue = value.map((val) => {
|
|
2703
|
-
if (typeof val ===
|
|
3045
|
+
if (typeof val === "object") {
|
|
2704
3046
|
return this.getCustomLabel(val);
|
|
2705
3047
|
}
|
|
2706
3048
|
return val;
|
|
@@ -2708,7 +3050,7 @@ class MultiSelectComponent extends BaseValueAccessor {
|
|
|
2708
3050
|
return optionsValue;
|
|
2709
3051
|
}
|
|
2710
3052
|
transformOptionValue(option) {
|
|
2711
|
-
const field = this.
|
|
3053
|
+
const field = this.field();
|
|
2712
3054
|
let optionValue;
|
|
2713
3055
|
optionValue = option[field.bindValue];
|
|
2714
3056
|
return optionValue;
|
|
@@ -2718,15 +3060,21 @@ class MultiSelectComponent extends BaseValueAccessor {
|
|
|
2718
3060
|
}
|
|
2719
3061
|
// Biến đổi label nếu có thuộc tính hàm biến đổi transformLabel.
|
|
2720
3062
|
getCustomLabel(option) {
|
|
2721
|
-
const field = this.
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
3063
|
+
const field = this.field();
|
|
3064
|
+
// 1. Ưu tiên lấy bindLabel, nếu không có thì fallback sang bindValue
|
|
3065
|
+
let rawLabel = option[field.bindLabel];
|
|
3066
|
+
if (rawLabel === undefined || rawLabel === null || rawLabel === "") {
|
|
3067
|
+
rawLabel = option[field.bindValue];
|
|
3068
|
+
}
|
|
3069
|
+
// 2. Kiểm tra nếu không tồn tại hoặc là dạng object/function (kể cả array)
|
|
3070
|
+
if (rawLabel === undefined ||
|
|
3071
|
+
rawLabel === null ||
|
|
3072
|
+
typeof rawLabel === "object" ||
|
|
3073
|
+
typeof rawLabel === "function") {
|
|
2727
3074
|
return NO_INFO_TEXT;
|
|
2728
3075
|
}
|
|
2729
|
-
let optionLabel =
|
|
3076
|
+
let optionLabel = String(rawLabel);
|
|
3077
|
+
// 3. Biến đổi theo transformLabel nếu có
|
|
2730
3078
|
if (field.transformLabel) {
|
|
2731
3079
|
const tranformLabelValue = field.transformLabel(option);
|
|
2732
3080
|
if (tranformLabelValue)
|
|
@@ -2741,194 +3089,101 @@ class MultiSelectComponent extends BaseValueAccessor {
|
|
|
2741
3089
|
useExisting: forwardRef(() => MultiSelectComponent),
|
|
2742
3090
|
multi: true,
|
|
2743
3091
|
},
|
|
2744
|
-
], usesInheritance: true, ngImport: i0, template: "<div class=\"flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
3092
|
+
], usesInheritance: true, ngImport: i0, template: "<div class=\"flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n @if (field().value!.length > 0) {\r\n <nz-select\r\n nzAllowClear\r\n [nzMode]=\"'multiple'\"\r\n [ngModel]=\"viewDisplayValue()\"\r\n [nzMaxTagCount]=\"field().maxTagCount!\"\r\n [nzMaxMultipleCount]=\"field().maxMultipleCount!\"\r\n [nzDisabled]=\"true\"\r\n >\r\n @for (displayOption of viewDisplayValue(); track $index) {\r\n <nz-option [nzValue]=\"displayOption\" [nzLabel]=\"displayOption\">\r\n </nz-option>\r\n }\r\n </nz-select>\r\n } @else {\r\n <input nz-input [value]=\"displayNoValueText\" [disabled]=\"true\" />\r\n }\r\n }\r\n\r\n @if (viewMode() === viewModeEnum.text) {\r\n @if (viewDisplayValue().length) {\r\n <ul class=\"view-list\">\r\n @for (label of viewDisplayValue(); track $index) {\r\n <li>{{ label }}</li>\r\n }\r\n </ul>\r\n } @else {\r\n <span class=\"modeView\">{{ displayNoValueText }}</span>\r\n }\r\n }\r\n } @else {\r\n <nz-select\r\n [id]=\"fieldKey()\"\r\n nzShowSearch\r\n nzAllowClear\r\n [nzDisabled]=\"disabled()\"\r\n [nzMode]=\"'multiple'\"\r\n [nzPlaceHolder]=\"displayPlaceholder()\"\r\n [nzMaxTagCount]=\"field().maxTagCount!\"\r\n [nzMaxMultipleCount]=\"field().maxMultipleCount!\"\r\n [nzSuffixIcon]=\"optionsResource.isLoading() ? loadingIcon : null\"\r\n [ngModel]=\"value\"\r\n (ngModelChange)=\"handleChangeOptions($event)\"\r\n >\r\n @for (\r\n option of options();\r\n track `${option[this.field().bindValue]}-${$index}`\r\n ) {\r\n <nz-option\r\n [nzValue]=\"transformOptionValue(option)\"\r\n [nzLabel]=\"getOptionLabel(option)\"\r\n >\r\n </nz-option>\r\n }\r\n </nz-select>\r\n\r\n <ng-template #loadingIcon>\r\n <nz-spin nzSimple [nzSize]=\"'small'\"></nz-spin>\r\n </ng-template>\r\n }\r\n\r\n <!-- Suffixes -->\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\" [formId]=\"formId\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n", styles: [".view-list{margin-bottom:0;padding-inline-start:24px!important}:host ::ng-deep .ant-input[disabled]{background-color:#fff;color:#575757!important}:host ::ng-deep .ant-select-multiple.ant-select-disabled.ant-select:not(.ant-select-customize-input) .ant-select-selector{background:#fff}:host ::ng-deep .ant-select-disabled.ant-select-multiple .ant-select-selection-item{color:#575757}\n"], dependencies: [{ kind: "ngmodule", type: i1$2.CommonModule }, { kind: "ngmodule", type: i1.FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "ngmodule", type: NzSelectModule }, { kind: "component", type: i3$1.NzOptionComponent, selector: "nz-option", inputs: ["nzTitle", "nzLabel", "nzValue", "nzKey", "nzDisabled", "nzHide", "nzCustomContent"], exportAs: ["nzOption"] }, { kind: "component", type: i3$1.NzSelectComponent, selector: "nz-select", inputs: ["nzId", "nzSize", "nzStatus", "nzOptionHeightPx", "nzOptionOverflowSize", "nzDropdownClassName", "nzDropdownMatchSelectWidth", "nzDropdownStyle", "nzNotFoundContent", "nzPlaceHolder", "nzPlacement", "nzMaxTagCount", "nzDropdownRender", "nzCustomTemplate", "nzSuffixIcon", "nzClearIcon", "nzRemoveIcon", "nzMenuItemSelectedIcon", "nzTokenSeparators", "nzMaxTagPlaceholder", "nzMaxMultipleCount", "nzMode", "nzFilterOption", "compareWith", "nzAllowClear", "nzBorderless", "nzShowSearch", "nzLoading", "nzAutoFocus", "nzAutoClearSearchValue", "nzServerSearch", "nzDisabled", "nzOpen", "nzSelectOnTab", "nzBackdrop", "nzOptions", "nzShowArrow"], outputs: ["nzOnSearch", "nzScrollToBottom", "nzOpenChange", "nzBlur", "nzFocus"], exportAs: ["nzSelect"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i1$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "ngmodule", type: NzSpinModule }, { kind: "component", type: i3$2.NzSpinComponent, selector: "nz-spin", inputs: ["nzIndicator", "nzSize", "nzTip", "nzDelay", "nzSimple", "nzSpinning"], exportAs: ["nzSpin"] }, { kind: "component", type: SuffixComponent, selector: "app-suffix", inputs: ["suffixConfig", "formId"] }] }); }
|
|
2745
3093
|
}
|
|
2746
3094
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MultiSelectComponent, decorators: [{
|
|
2747
3095
|
type: Component,
|
|
2748
|
-
args: [{ selector:
|
|
3096
|
+
args: [{ selector: "app-multi-select", standalone: true, imports: [...CORE_MODULES, ...FORM_MODULES, ...ZORRO_MODULES$5, ...COMPONENTS$2], providers: [
|
|
2749
3097
|
{
|
|
2750
3098
|
provide: NG_VALUE_ACCESSOR,
|
|
2751
3099
|
useExisting: forwardRef(() => MultiSelectComponent),
|
|
2752
3100
|
multi: true,
|
|
2753
3101
|
},
|
|
2754
|
-
], template: "<div class=\"flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
3102
|
+
], template: "<div class=\"flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n @if (field().value!.length > 0) {\r\n <nz-select\r\n nzAllowClear\r\n [nzMode]=\"'multiple'\"\r\n [ngModel]=\"viewDisplayValue()\"\r\n [nzMaxTagCount]=\"field().maxTagCount!\"\r\n [nzMaxMultipleCount]=\"field().maxMultipleCount!\"\r\n [nzDisabled]=\"true\"\r\n >\r\n @for (displayOption of viewDisplayValue(); track $index) {\r\n <nz-option [nzValue]=\"displayOption\" [nzLabel]=\"displayOption\">\r\n </nz-option>\r\n }\r\n </nz-select>\r\n } @else {\r\n <input nz-input [value]=\"displayNoValueText\" [disabled]=\"true\" />\r\n }\r\n }\r\n\r\n @if (viewMode() === viewModeEnum.text) {\r\n @if (viewDisplayValue().length) {\r\n <ul class=\"view-list\">\r\n @for (label of viewDisplayValue(); track $index) {\r\n <li>{{ label }}</li>\r\n }\r\n </ul>\r\n } @else {\r\n <span class=\"modeView\">{{ displayNoValueText }}</span>\r\n }\r\n }\r\n } @else {\r\n <nz-select\r\n [id]=\"fieldKey()\"\r\n nzShowSearch\r\n nzAllowClear\r\n [nzDisabled]=\"disabled()\"\r\n [nzMode]=\"'multiple'\"\r\n [nzPlaceHolder]=\"displayPlaceholder()\"\r\n [nzMaxTagCount]=\"field().maxTagCount!\"\r\n [nzMaxMultipleCount]=\"field().maxMultipleCount!\"\r\n [nzSuffixIcon]=\"optionsResource.isLoading() ? loadingIcon : null\"\r\n [ngModel]=\"value\"\r\n (ngModelChange)=\"handleChangeOptions($event)\"\r\n >\r\n @for (\r\n option of options();\r\n track `${option[this.field().bindValue]}-${$index}`\r\n ) {\r\n <nz-option\r\n [nzValue]=\"transformOptionValue(option)\"\r\n [nzLabel]=\"getOptionLabel(option)\"\r\n >\r\n </nz-option>\r\n }\r\n </nz-select>\r\n\r\n <ng-template #loadingIcon>\r\n <nz-spin nzSimple [nzSize]=\"'small'\"></nz-spin>\r\n </ng-template>\r\n }\r\n\r\n <!-- Suffixes -->\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\" [formId]=\"formId\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n", styles: [".view-list{margin-bottom:0;padding-inline-start:24px!important}:host ::ng-deep .ant-input[disabled]{background-color:#fff;color:#575757!important}:host ::ng-deep .ant-select-multiple.ant-select-disabled.ant-select:not(.ant-select-customize-input) .ant-select-selector{background:#fff}:host ::ng-deep .ant-select-disabled.ant-select-multiple .ant-select-selection-item{color:#575757}\n"] }]
|
|
2755
3103
|
}], ctorParameters: () => [] });
|
|
2756
3104
|
|
|
2757
|
-
const
|
|
2758
|
-
const
|
|
2759
|
-
|
|
3105
|
+
const modules$3 = [CommonModule, FormsModule, ReactiveFormsModule];
|
|
3106
|
+
const zorroModules$3 = [NzSelectModule, NzSpinModule, NzInputModule];
|
|
3107
|
+
const components$2 = [SuffixComponent];
|
|
3108
|
+
class SingleSelectComponent extends BaseSelectComponent {
|
|
2760
3109
|
constructor() {
|
|
2761
3110
|
super();
|
|
2762
|
-
this.
|
|
3111
|
+
this.field = computed(() => {
|
|
2763
3112
|
const base = this.fieldInput();
|
|
2764
3113
|
if (!(base instanceof SingleSelectField) ||
|
|
2765
|
-
(base.type !== FieldTypeEnum.SingleSelect &&
|
|
2766
|
-
|
|
3114
|
+
(base.type !== FieldTypeEnum.SingleSelect &&
|
|
3115
|
+
base.controlType !== ControlTypeEnum.Select)) {
|
|
3116
|
+
throw new Error("Expected SingleSelectField");
|
|
2767
3117
|
}
|
|
2768
3118
|
return base;
|
|
2769
3119
|
});
|
|
2770
3120
|
// Giá trị dùng hiển thị ở chế độ View.
|
|
2771
|
-
this.
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
this.options = [];
|
|
2776
|
-
this.queryParams = {};
|
|
2777
|
-
// 1. Effect chung Add + Edit
|
|
2778
|
-
effect(() => {
|
|
2779
|
-
if (this.isAddOrEdit()) {
|
|
2780
|
-
const field = untracked(() => this.fieldSignal());
|
|
2781
|
-
const { placeholder } = field;
|
|
2782
|
-
if (!placeholder)
|
|
2783
|
-
field.placeholder = createSelectPlaceholder(field);
|
|
2784
|
-
}
|
|
2785
|
-
});
|
|
2786
|
-
// Trigger reset từ bên ngoài form.
|
|
2787
|
-
effect(() => {
|
|
2788
|
-
const reset = this.dFormService.resetTrigger();
|
|
2789
|
-
if (reset?.formId === this.formId) {
|
|
2790
|
-
this.reset();
|
|
2791
|
-
}
|
|
2792
|
-
});
|
|
2793
|
-
effect(() => {
|
|
2794
|
-
if (untracked(() => this.isView()))
|
|
2795
|
-
return;
|
|
2796
|
-
const { key, dependsOn, isParent, dependType } = untracked(() => this.fieldSignal());
|
|
2797
|
-
// Không dính dáng gì đến isParent và dependsOn.
|
|
2798
|
-
if (!isParent && dependsOn.length === 0) {
|
|
2799
|
-
this.getOptions();
|
|
2800
|
-
return;
|
|
2801
|
-
}
|
|
2802
|
-
const dependValuesMap = this.fieldService.getDependValuesMap();
|
|
2803
|
-
const dependValues = dependsOn?.map(depend => {
|
|
2804
|
-
const dependFunc = dependValuesMap.get(depend.fieldKey);
|
|
2805
|
-
const value = typeof dependFunc === 'function' ? dependFunc() : dependFunc;
|
|
2806
|
-
return [depend.paramKey, value];
|
|
2807
|
-
});
|
|
2808
|
-
// console.log(`${key} dependValue`, dependValues);
|
|
2809
|
-
const params = Object.fromEntries(dependValues);
|
|
2810
|
-
this.queryParams = {
|
|
2811
|
-
...this.queryParams,
|
|
2812
|
-
...params,
|
|
2813
|
-
};
|
|
2814
|
-
// console.log(`${key} queryParams`, this.queryParams);
|
|
2815
|
-
// Nếu tất cả các phụ thuộc có value thì mới gọi API.
|
|
2816
|
-
const allDependHasValues = dependValues?.every(([fieldKey, value]) => value);
|
|
2817
|
-
// console.log(`${key} allDependHasValues`, allDependHasValues);
|
|
2818
|
-
if (allDependHasValues) {
|
|
2819
|
-
// this.isDisabledSignal.set(false);
|
|
2820
|
-
this.control?.enable();
|
|
2821
|
-
this.getOptions();
|
|
2822
|
-
}
|
|
2823
|
-
else {
|
|
2824
|
-
// Ngược lại reset và disabled.
|
|
2825
|
-
this.control?.reset();
|
|
2826
|
-
// this.isDisabledSignal.set(true);
|
|
2827
|
-
this.control?.disable();
|
|
2828
|
-
}
|
|
3121
|
+
this.viewDisplayValue = computed(() => {
|
|
3122
|
+
if (!this.isView())
|
|
3123
|
+
return "";
|
|
3124
|
+
return this.getDisplayValue(this.field().modelValue || this.valueSignal());
|
|
2829
3125
|
});
|
|
2830
3126
|
}
|
|
3127
|
+
onApiOptionsLoaded() {
|
|
3128
|
+
const field = this.field();
|
|
3129
|
+
if (field.outputAs === SelectOutputValueTypeEnum.SourceObject) {
|
|
3130
|
+
const newOutputValue = this.value && this.getValueByOutputAs(this.value);
|
|
3131
|
+
this.patchFormData(this.fieldKey(), newOutputValue);
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
// Xử lý tạo placeholder text tự động nếu chưa truyền placeholder vào config của field
|
|
3135
|
+
resolvePlaceholderText() {
|
|
3136
|
+
return createSingleSelectPlaceholder(this.field());
|
|
3137
|
+
}
|
|
2831
3138
|
// Chạy khi value form được gán bởi các hàm reset, patchValue, setValue.
|
|
2832
3139
|
writeValueToView(value) {
|
|
2833
|
-
if (this.isView()) {
|
|
2834
|
-
this.displayValue = this.getDisplayValue(this.fieldSignal().modelValue);
|
|
2835
|
-
return;
|
|
2836
|
-
}
|
|
2837
3140
|
if (!this.isAddOrEdit())
|
|
2838
3141
|
return;
|
|
2839
|
-
|
|
2840
|
-
//
|
|
2841
|
-
//
|
|
3142
|
+
// Bắn giá trị mới vào BehaviorSubject của FieldService.
|
|
3143
|
+
// Việc này báo cho các component Con biết Parent vừa thay đổi data.
|
|
3144
|
+
// Lợi ích: Dòng data chạy thẳng đứng (Push) vào ống, không phụ thuộc vào Signal tracking ẩn.
|
|
3145
|
+
this.fieldService.emitDependValueChange(this.fieldKey(), value ?? "");
|
|
2842
3146
|
// Gán data vào đầu ra của form.
|
|
2843
3147
|
const newOutputValue = value && this.getValueByOutputAs(value);
|
|
2844
3148
|
this.patchFormData(this.fieldKey(), newOutputValue);
|
|
2845
3149
|
}
|
|
2846
3150
|
// Xử lý phụ thuộc khi change value
|
|
2847
3151
|
handleValueChange(value) {
|
|
2848
|
-
const { isParent } = this.
|
|
3152
|
+
const { isParent } = this.field();
|
|
2849
3153
|
if (isParent) {
|
|
2850
|
-
this.fieldService.
|
|
2851
|
-
// const signal = untracked(() => this.fieldService.getDependValuesMap().get(this.fieldKey()))
|
|
2852
|
-
// console.log("DependValuesMap UI", untracked(() => signal!()));
|
|
3154
|
+
this.fieldService.emitDependValueChange(this.fieldKey(), value);
|
|
2853
3155
|
}
|
|
2854
3156
|
// Gán data vào đầu ra của form.
|
|
2855
3157
|
const newOutputValue = value && this.getValueByOutputAs(value);
|
|
2856
3158
|
this.patchFormData(this.fieldKey(), newOutputValue);
|
|
2857
3159
|
}
|
|
2858
|
-
createFullApiUrl() {
|
|
2859
|
-
const field = untracked(() => this.fieldSignal());
|
|
2860
|
-
let fullApiUrl = field?.apiConfig?.baseUrl || '';
|
|
2861
|
-
const params = field?.apiConfig?.params || {};
|
|
2862
|
-
this.queryParams = {
|
|
2863
|
-
...this.queryParams,
|
|
2864
|
-
...params,
|
|
2865
|
-
};
|
|
2866
|
-
return fullApiUrl;
|
|
2867
|
-
}
|
|
2868
|
-
// Lấy danh sách options từ GET api.
|
|
2869
|
-
getOptions() {
|
|
2870
|
-
const field = untracked(() => this.fieldSignal());
|
|
2871
|
-
const { optionsToPrepend, optionsToAppend, exceptOptions } = field;
|
|
2872
|
-
const fullApiUrl = this.createFullApiUrl();
|
|
2873
|
-
if (!fullApiUrl) {
|
|
2874
|
-
this.options = field?.options ?? [];
|
|
2875
|
-
this.options = [...optionsToPrepend, ...this.options, ...optionsToAppend].filter(options => !exceptOptions.some(opts => opts[field.bindValue] === options[field.bindValue]));
|
|
2876
|
-
return;
|
|
2877
|
-
}
|
|
2878
|
-
this.loadingSignal.set(true);
|
|
2879
|
-
this.control?.disable();
|
|
2880
|
-
this.fieldService
|
|
2881
|
-
.getAllOptions(fullApiUrl, this.queryParams)
|
|
2882
|
-
.pipe(this.takeUntilDestroy())
|
|
2883
|
-
.subscribe({
|
|
2884
|
-
next: (res) => {
|
|
2885
|
-
this.loadingSignal.set(false);
|
|
2886
|
-
if (!this.fieldSignal().isDisabled)
|
|
2887
|
-
this.control?.enable();
|
|
2888
|
-
if (res?.code === 0) {
|
|
2889
|
-
this.options = res?.data;
|
|
2890
|
-
this.options = [...optionsToPrepend, ...this.options, ...optionsToAppend].filter(options => !exceptOptions.some(opts => opts[field.bindValue] === options[field.bindValue]));
|
|
2891
|
-
// Nếu outputAs là dạng sourceObject đồng bộ sau khi load xong list.
|
|
2892
|
-
if (field.outputAs === SelectOutputValueTypeEnum.SourceObject) {
|
|
2893
|
-
const newOutputValue = this.options.find(option => option[field.bindValue] === this.value) ?? {
|
|
2894
|
-
[field.bindValue]: this.value,
|
|
2895
|
-
};
|
|
2896
|
-
this.patchFormData(this.fieldKey(), newOutputValue);
|
|
2897
|
-
}
|
|
2898
|
-
}
|
|
2899
|
-
},
|
|
2900
|
-
error: (error) => {
|
|
2901
|
-
this.loadingSignal.set(false);
|
|
2902
|
-
if (!this.fieldSignal().isDisabled)
|
|
2903
|
-
this.control?.enable();
|
|
2904
|
-
},
|
|
2905
|
-
});
|
|
2906
|
-
}
|
|
2907
3160
|
handleChangeOptions(optionValue) {
|
|
2908
|
-
const { enableFieldChange, bindValue } = untracked(() => this.
|
|
3161
|
+
const { enableFieldChange, bindValue } = untracked(() => this.field());
|
|
2909
3162
|
if (enableFieldChange) {
|
|
2910
|
-
const option = this.options.find(option => option[bindValue] === optionValue);
|
|
3163
|
+
const option = this.options().find((option) => option[bindValue] === optionValue);
|
|
2911
3164
|
this.fieldService.onFieldChange(this.fieldKey(), option);
|
|
2912
3165
|
}
|
|
2913
3166
|
this.propagateValue(optionValue);
|
|
2914
3167
|
}
|
|
2915
3168
|
// Xử lý output value đầu ra theo outputAs mà người dùng mong muốn.
|
|
2916
3169
|
getValueByOutputAs(singleValue) {
|
|
2917
|
-
const
|
|
3170
|
+
const { outputAs, bindValue, bindLabel, modelValue } = this.field();
|
|
2918
3171
|
if (singleValue) {
|
|
2919
3172
|
// Nếu outputAs là dạng single.
|
|
2920
3173
|
let value = singleValue;
|
|
2921
3174
|
// Nếu outputAs là dạng object.
|
|
2922
|
-
if (
|
|
3175
|
+
if (outputAs === SelectOutputValueTypeEnum.Object) {
|
|
2923
3176
|
value = {
|
|
2924
|
-
[
|
|
3177
|
+
[bindValue]: singleValue,
|
|
2925
3178
|
};
|
|
2926
3179
|
}
|
|
2927
3180
|
// Nếu outputAs là dạng sourceObject.
|
|
2928
|
-
if (
|
|
2929
|
-
value =
|
|
2930
|
-
[
|
|
2931
|
-
|
|
3181
|
+
if (outputAs === SelectOutputValueTypeEnum.SourceObject) {
|
|
3182
|
+
value =
|
|
3183
|
+
this.options().find((option) => option[bindValue] === singleValue) ??
|
|
3184
|
+
(modelValue && typeof modelValue === "object"
|
|
3185
|
+
? modelValue
|
|
3186
|
+
: { [bindValue]: value });
|
|
2932
3187
|
}
|
|
2933
3188
|
return value;
|
|
2934
3189
|
}
|
|
@@ -2938,14 +3193,14 @@ class SingleSelectComponent extends BaseValueAccessor {
|
|
|
2938
3193
|
getDisplayValue(value) {
|
|
2939
3194
|
if (!value)
|
|
2940
3195
|
return NO_INFO_TEXT;
|
|
2941
|
-
if (typeof value ===
|
|
3196
|
+
if (typeof value === "object") {
|
|
2942
3197
|
return this.getCustomLabel(value);
|
|
2943
3198
|
}
|
|
2944
3199
|
return value;
|
|
2945
3200
|
}
|
|
2946
3201
|
// Lấy value ở option tag.
|
|
2947
3202
|
transformOptionValue(option) {
|
|
2948
|
-
const field = this.
|
|
3203
|
+
const field = this.field();
|
|
2949
3204
|
let optionValue;
|
|
2950
3205
|
optionValue = option[field.bindValue];
|
|
2951
3206
|
return optionValue;
|
|
@@ -2956,15 +3211,21 @@ class SingleSelectComponent extends BaseValueAccessor {
|
|
|
2956
3211
|
}
|
|
2957
3212
|
// Biến đổi label nếu có thuộc tính hàm biến đổi transformLabel.
|
|
2958
3213
|
getCustomLabel(option) {
|
|
2959
|
-
const field = this.
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
3214
|
+
const field = this.field();
|
|
3215
|
+
// 1. Ưu tiên lấy bindLabel, nếu không có thì fallback sang bindValue
|
|
3216
|
+
let rawLabel = option[field.bindLabel];
|
|
3217
|
+
if (rawLabel === undefined || rawLabel === null || rawLabel === "") {
|
|
3218
|
+
rawLabel = option[field.bindValue];
|
|
3219
|
+
}
|
|
3220
|
+
// 2. Kiểm tra nếu không tồn tại hoặc là dạng object/function (kể cả array)
|
|
3221
|
+
if (rawLabel === undefined ||
|
|
3222
|
+
rawLabel === null ||
|
|
3223
|
+
typeof rawLabel === "object" ||
|
|
3224
|
+
typeof rawLabel === "function") {
|
|
2965
3225
|
return NO_INFO_TEXT;
|
|
2966
3226
|
}
|
|
2967
|
-
let optionLabel =
|
|
3227
|
+
let optionLabel = String(rawLabel);
|
|
3228
|
+
// 3. Biến đổi theo transformLabel nếu có
|
|
2968
3229
|
if (field.transformLabel) {
|
|
2969
3230
|
const tranformLabelValue = field.transformLabel(option);
|
|
2970
3231
|
if (tranformLabelValue)
|
|
@@ -2979,36 +3240,37 @@ class SingleSelectComponent extends BaseValueAccessor {
|
|
|
2979
3240
|
useExisting: forwardRef(() => SingleSelectComponent),
|
|
2980
3241
|
multi: true,
|
|
2981
3242
|
},
|
|
2982
|
-
], usesInheritance: true, ngImport: i0, template: "<div class=\"d-flex\">\r\n @if (
|
|
3243
|
+
], usesInheritance: true, ngImport: i0, template: "<div class=\"d-flex\">\r\n @if (isView()) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n <input\r\n [title]=\"viewDisplayValue()\"\r\n nz-input\r\n [value]=\"viewDisplayValue()\"\r\n class=\"modeView\"\r\n />\r\n }\r\n @if (viewMode() === viewModeEnum.text) {\r\n <span [title]=\"viewDisplayValue()\" class=\"modeView break-work\">{{\r\n viewDisplayValue()\r\n }}</span>\r\n }\r\n } @else {\r\n <nz-select\r\n [id]=\"fieldKey()\"\r\n nzShowSearch\r\n nzAllowClear\r\n [nzDisabled]=\"disabled()\"\r\n [nzPlaceHolder]=\"displayPlaceholder()\"\r\n [nzSuffixIcon]=\"optionsResource.isLoading() ? loadingIcon : null\"\r\n [title]=\"field().tooltip || ''\"\r\n [nzDropdownMatchSelectWidth]=\"field().matchSelectWidth\"\r\n [ngModel]=\"value\"\r\n class=\"flex-1 min-w-0\"\r\n (ngModelChange)=\"handleChangeOptions($event)\"\r\n >\r\n @for (\r\n option of options();\r\n track `${option[this.field().bindValue]}-${$index}`\r\n ) {\r\n <nz-option\r\n [nzValue]=\"transformOptionValue(option)\"\r\n [nzLabel]=\"getOptionLabel(option)\"\r\n >\r\n </nz-option>\r\n }\r\n </nz-select>\r\n\r\n <ng-template #loadingIcon>\r\n <nz-spin nzSimple [nzSize]=\"'small'\"></nz-spin>\r\n </ng-template>\r\n }\r\n\r\n <!-- Suffixes -->\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\" [formId]=\"formId\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: NzSelectModule }, { kind: "component", type: i3$1.NzOptionComponent, selector: "nz-option", inputs: ["nzTitle", "nzLabel", "nzValue", "nzKey", "nzDisabled", "nzHide", "nzCustomContent"], exportAs: ["nzOption"] }, { kind: "component", type: i3$1.NzSelectComponent, selector: "nz-select", inputs: ["nzId", "nzSize", "nzStatus", "nzOptionHeightPx", "nzOptionOverflowSize", "nzDropdownClassName", "nzDropdownMatchSelectWidth", "nzDropdownStyle", "nzNotFoundContent", "nzPlaceHolder", "nzPlacement", "nzMaxTagCount", "nzDropdownRender", "nzCustomTemplate", "nzSuffixIcon", "nzClearIcon", "nzRemoveIcon", "nzMenuItemSelectedIcon", "nzTokenSeparators", "nzMaxTagPlaceholder", "nzMaxMultipleCount", "nzMode", "nzFilterOption", "compareWith", "nzAllowClear", "nzBorderless", "nzShowSearch", "nzLoading", "nzAutoFocus", "nzAutoClearSearchValue", "nzServerSearch", "nzDisabled", "nzOpen", "nzSelectOnTab", "nzBackdrop", "nzOptions", "nzShowArrow"], outputs: ["nzOnSearch", "nzScrollToBottom", "nzOpenChange", "nzBlur", "nzFocus"], exportAs: ["nzSelect"] }, { kind: "ngmodule", type: NzSpinModule }, { kind: "component", type: i3$2.NzSpinComponent, selector: "nz-spin", inputs: ["nzIndicator", "nzSize", "nzTip", "nzDelay", "nzSimple", "nzSpinning"], exportAs: ["nzSpin"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i1$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "component", type: SuffixComponent, selector: "app-suffix", inputs: ["suffixConfig", "formId"] }] }); }
|
|
2983
3244
|
}
|
|
2984
3245
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: SingleSelectComponent, decorators: [{
|
|
2985
3246
|
type: Component,
|
|
2986
|
-
args: [{ selector:
|
|
3247
|
+
args: [{ selector: "app-single-select", standalone: true, imports: [...modules$3, ...zorroModules$3, ...components$2], providers: [
|
|
2987
3248
|
{
|
|
2988
3249
|
provide: NG_VALUE_ACCESSOR,
|
|
2989
3250
|
useExisting: forwardRef(() => SingleSelectComponent),
|
|
2990
3251
|
multi: true,
|
|
2991
3252
|
},
|
|
2992
|
-
], template: "<div class=\"d-flex\">\r\n @if (
|
|
3253
|
+
], template: "<div class=\"d-flex\">\r\n @if (isView()) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n <input\r\n [title]=\"viewDisplayValue()\"\r\n nz-input\r\n [value]=\"viewDisplayValue()\"\r\n class=\"modeView\"\r\n />\r\n }\r\n @if (viewMode() === viewModeEnum.text) {\r\n <span [title]=\"viewDisplayValue()\" class=\"modeView break-work\">{{\r\n viewDisplayValue()\r\n }}</span>\r\n }\r\n } @else {\r\n <nz-select\r\n [id]=\"fieldKey()\"\r\n nzShowSearch\r\n nzAllowClear\r\n [nzDisabled]=\"disabled()\"\r\n [nzPlaceHolder]=\"displayPlaceholder()\"\r\n [nzSuffixIcon]=\"optionsResource.isLoading() ? loadingIcon : null\"\r\n [title]=\"field().tooltip || ''\"\r\n [nzDropdownMatchSelectWidth]=\"field().matchSelectWidth\"\r\n [ngModel]=\"value\"\r\n class=\"flex-1 min-w-0\"\r\n (ngModelChange)=\"handleChangeOptions($event)\"\r\n >\r\n @for (\r\n option of options();\r\n track `${option[this.field().bindValue]}-${$index}`\r\n ) {\r\n <nz-option\r\n [nzValue]=\"transformOptionValue(option)\"\r\n [nzLabel]=\"getOptionLabel(option)\"\r\n >\r\n </nz-option>\r\n }\r\n </nz-select>\r\n\r\n <ng-template #loadingIcon>\r\n <nz-spin nzSimple [nzSize]=\"'small'\"></nz-spin>\r\n </ng-template>\r\n }\r\n\r\n <!-- Suffixes -->\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\" [formId]=\"formId\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n" }]
|
|
2993
3254
|
}], ctorParameters: () => [], propDecorators: { isCustomInputText: [{
|
|
2994
3255
|
type: Input
|
|
2995
3256
|
}] } });
|
|
2996
3257
|
|
|
2997
|
-
const ZORRO_MODULES$
|
|
2998
|
-
const COMPONENTS$
|
|
3258
|
+
const ZORRO_MODULES$4 = [NzTreeSelectModule, NzSpinModule, NzInputModule];
|
|
3259
|
+
const COMPONENTS$1 = [SuffixComponent];
|
|
2999
3260
|
class TreeSelectComponent extends BaseValueAccessor {
|
|
3000
3261
|
constructor() {
|
|
3001
3262
|
super();
|
|
3002
|
-
this.
|
|
3263
|
+
this.field = computed(() => {
|
|
3003
3264
|
const base = this.fieldInput();
|
|
3004
3265
|
if (!(base instanceof TreeSelectField) ||
|
|
3005
|
-
(base.type !== FieldTypeEnum.TreeSelect &&
|
|
3006
|
-
|
|
3266
|
+
(base.type !== FieldTypeEnum.TreeSelect &&
|
|
3267
|
+
base.controlType !== ControlTypeEnum.Select)) {
|
|
3268
|
+
throw new Error("Expected TreeSelectField");
|
|
3007
3269
|
}
|
|
3008
3270
|
return base;
|
|
3009
3271
|
});
|
|
3010
3272
|
// Giá trị dùng hiển thị ở chế độ View.
|
|
3011
|
-
this.displayValue =
|
|
3273
|
+
this.displayValue = "";
|
|
3012
3274
|
this.loadingSignal = signal(false);
|
|
3013
3275
|
this.isDisabledSignal = signal(false);
|
|
3014
3276
|
this.disabled = computed(() => this.loadingSignal() || this.isDisabledSignal());
|
|
@@ -3017,7 +3279,7 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3017
3279
|
// 1. Effect chung Add + Edit
|
|
3018
3280
|
effect(() => {
|
|
3019
3281
|
if (this.isAddOrEdit()) {
|
|
3020
|
-
const field = untracked(() => this.
|
|
3282
|
+
const field = untracked(() => this.field());
|
|
3021
3283
|
const { placeholder } = field;
|
|
3022
3284
|
if (!placeholder)
|
|
3023
3285
|
field.placeholder = createSelectPlaceholder(field);
|
|
@@ -3033,16 +3295,16 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3033
3295
|
effect(() => {
|
|
3034
3296
|
if (untracked(() => this.isView()))
|
|
3035
3297
|
return;
|
|
3036
|
-
const { key, dependsOn, isParent, dependType } = untracked(() => this.
|
|
3298
|
+
const { key, dependsOn, isParent, dependType } = untracked(() => this.field());
|
|
3037
3299
|
// Không dính dáng gì đến isParent và dependsOn.
|
|
3038
3300
|
if (!isParent && dependsOn.length === 0) {
|
|
3039
3301
|
this.getOptions();
|
|
3040
3302
|
return;
|
|
3041
3303
|
}
|
|
3042
3304
|
const dependValuesMap = this.fieldService.getDependValuesMap();
|
|
3043
|
-
const dependValues = dependsOn?.map(depend => {
|
|
3305
|
+
const dependValues = dependsOn?.map((depend) => {
|
|
3044
3306
|
const dependFunc = dependValuesMap.get(depend.fieldKey);
|
|
3045
|
-
const value = typeof dependFunc ===
|
|
3307
|
+
const value = typeof dependFunc === "function" ? dependFunc() : dependFunc;
|
|
3046
3308
|
return [depend.paramKey, value];
|
|
3047
3309
|
});
|
|
3048
3310
|
// console.log(`${key} dependValue`, dependValues);
|
|
@@ -3068,15 +3330,19 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3068
3330
|
}
|
|
3069
3331
|
});
|
|
3070
3332
|
}
|
|
3333
|
+
// Xử lý tạo placeholder text tự động nếu chưa truyền placeholder vào config của field
|
|
3334
|
+
resolvePlaceholderText() {
|
|
3335
|
+
return createSingleSelectPlaceholder(this.field());
|
|
3336
|
+
}
|
|
3071
3337
|
// Chạy khi value form được gán bởi các hàm reset, patchValue, setValue.
|
|
3072
3338
|
writeValueToView(value) {
|
|
3073
3339
|
if (this.isView()) {
|
|
3074
|
-
this.displayValue = this.getDisplayValue(this.
|
|
3340
|
+
this.displayValue = this.getDisplayValue(this.field().modelValue);
|
|
3075
3341
|
return;
|
|
3076
3342
|
}
|
|
3077
3343
|
if (!this.isAddOrEdit())
|
|
3078
3344
|
return;
|
|
3079
|
-
this.fieldService.updateDependValuesMap(this.fieldKey(), value ??
|
|
3345
|
+
this.fieldService.updateDependValuesMap(this.fieldKey(), value ?? "");
|
|
3080
3346
|
// const signal = untracked(() => this.fieldService.getDependValuesMap().get(this.fieldKey()))
|
|
3081
3347
|
// console.log("DependValuesMap SET", untracked(() => signal!()));
|
|
3082
3348
|
// Gán data vào đầu ra của form.
|
|
@@ -3085,7 +3351,7 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3085
3351
|
}
|
|
3086
3352
|
// Xử lý phụ thuộc khi change value
|
|
3087
3353
|
handleValueChange(value) {
|
|
3088
|
-
const { isParent } = this.
|
|
3354
|
+
const { isParent } = this.field();
|
|
3089
3355
|
if (isParent) {
|
|
3090
3356
|
this.fieldService.updateDependValuesMap(this.fieldKey(), value);
|
|
3091
3357
|
// const signal = untracked(() => this.fieldService.getDependValuesMap().get(this.fieldKey()))
|
|
@@ -3096,8 +3362,8 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3096
3362
|
this.patchFormData(this.fieldKey(), newOutputValue);
|
|
3097
3363
|
}
|
|
3098
3364
|
createFullApiUrl() {
|
|
3099
|
-
const field = untracked(() => this.
|
|
3100
|
-
let fullApiUrl = field?.apiConfig?.baseUrl ||
|
|
3365
|
+
const field = untracked(() => this.field());
|
|
3366
|
+
let fullApiUrl = field?.apiConfig?.baseUrl || "";
|
|
3101
3367
|
const params = field?.apiConfig?.params || {};
|
|
3102
3368
|
this.queryParams = {
|
|
3103
3369
|
...this.queryParams,
|
|
@@ -3121,8 +3387,8 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3121
3387
|
}
|
|
3122
3388
|
// Step 2: Build parent-child relation
|
|
3123
3389
|
for (const node of map.values()) {
|
|
3124
|
-
if (node[
|
|
3125
|
-
const parent = map.get(node[
|
|
3390
|
+
if (node["parentCode"]) {
|
|
3391
|
+
const parent = map.get(node["parentCode"]);
|
|
3126
3392
|
if (parent) {
|
|
3127
3393
|
if (!parent.children)
|
|
3128
3394
|
parent.children = [];
|
|
@@ -3141,11 +3407,15 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3141
3407
|
}
|
|
3142
3408
|
// Lấy danh sách options từ GET api.
|
|
3143
3409
|
getOptions() {
|
|
3144
|
-
const field = untracked(() => this.
|
|
3410
|
+
const field = untracked(() => this.field());
|
|
3145
3411
|
const { optionsToPrepend, optionsToAppend, exceptOptions } = field;
|
|
3146
3412
|
const fullApiUrl = this.createFullApiUrl();
|
|
3147
3413
|
if (!fullApiUrl) {
|
|
3148
|
-
const options = [
|
|
3414
|
+
const options = [
|
|
3415
|
+
...optionsToPrepend,
|
|
3416
|
+
...field.options,
|
|
3417
|
+
...optionsToAppend,
|
|
3418
|
+
].filter((options) => !exceptOptions.some((opts) => opts[field.bindValue] === options[field.bindValue]));
|
|
3149
3419
|
this.options = this.buildTree(options, field.groupBy);
|
|
3150
3420
|
return;
|
|
3151
3421
|
}
|
|
@@ -3157,14 +3427,18 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3157
3427
|
.subscribe({
|
|
3158
3428
|
next: (res) => {
|
|
3159
3429
|
this.loadingSignal.set(false);
|
|
3160
|
-
if (!this.
|
|
3430
|
+
if (!this.field().isDisabled)
|
|
3161
3431
|
this.control?.enable();
|
|
3162
3432
|
if (res?.code === 0) {
|
|
3163
|
-
const options = [
|
|
3433
|
+
const options = [
|
|
3434
|
+
...optionsToPrepend,
|
|
3435
|
+
...(res?.data ?? []),
|
|
3436
|
+
...optionsToAppend,
|
|
3437
|
+
].filter((options) => !exceptOptions.some((opts) => opts[field.bindValue] === options[field.bindValue]));
|
|
3164
3438
|
this.options = this.buildTree(options, field.groupBy);
|
|
3165
3439
|
// Nếu outputAs là dạng sourceObject đồng bộ sau khi load xong list.
|
|
3166
3440
|
if (field.outputAs === SelectOutputValueTypeEnum.SourceObject) {
|
|
3167
|
-
const newOutputValue = this.options.find(option => option.key === this.value) ?? {
|
|
3441
|
+
const newOutputValue = this.options.find((option) => option.key === this.value) ?? {
|
|
3168
3442
|
[field.bindValue]: this.value,
|
|
3169
3443
|
};
|
|
3170
3444
|
this.patchFormData(this.fieldKey(), newOutputValue);
|
|
@@ -3173,22 +3447,22 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3173
3447
|
},
|
|
3174
3448
|
error: (error) => {
|
|
3175
3449
|
this.loadingSignal.set(false);
|
|
3176
|
-
if (!this.
|
|
3450
|
+
if (!this.field().isDisabled)
|
|
3177
3451
|
this.control?.enable();
|
|
3178
3452
|
},
|
|
3179
3453
|
});
|
|
3180
3454
|
}
|
|
3181
3455
|
handleChangeOptions(optionValue) {
|
|
3182
|
-
const { enableFieldChange, bindValue } = untracked(() => this.
|
|
3456
|
+
const { enableFieldChange, bindValue } = untracked(() => this.field());
|
|
3183
3457
|
if (enableFieldChange) {
|
|
3184
|
-
const option = this.options.find(option => option[bindValue] === optionValue);
|
|
3458
|
+
const option = this.options.find((option) => option[bindValue] === optionValue);
|
|
3185
3459
|
this.fieldService.onFieldChange(this.fieldKey(), option);
|
|
3186
3460
|
}
|
|
3187
3461
|
this.propagateValue(optionValue);
|
|
3188
3462
|
}
|
|
3189
3463
|
// Xử lý output value đầu ra theo outputAs mà người dùng mong muốn.
|
|
3190
3464
|
getValueByOutputAs(singleValue) {
|
|
3191
|
-
const field = this.
|
|
3465
|
+
const field = this.field();
|
|
3192
3466
|
if (singleValue) {
|
|
3193
3467
|
// Nếu outputAs là dạng single.
|
|
3194
3468
|
let value = singleValue;
|
|
@@ -3200,7 +3474,7 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3200
3474
|
}
|
|
3201
3475
|
// Nếu outputAs là dạng sourceObject.
|
|
3202
3476
|
if (field.outputAs === SelectOutputValueTypeEnum.SourceObject) {
|
|
3203
|
-
value = this.options.find(option => option[field.bindValue] === singleValue) ?? {
|
|
3477
|
+
value = this.options.find((option) => option[field.bindValue] === singleValue) ?? {
|
|
3204
3478
|
[field.bindValue]: singleValue,
|
|
3205
3479
|
};
|
|
3206
3480
|
}
|
|
@@ -3212,14 +3486,14 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3212
3486
|
getDisplayValue(value) {
|
|
3213
3487
|
if (!value)
|
|
3214
3488
|
return NO_INFO_TEXT;
|
|
3215
|
-
if (typeof value ===
|
|
3489
|
+
if (typeof value === "object") {
|
|
3216
3490
|
return this.getCustomLabel(value);
|
|
3217
3491
|
}
|
|
3218
3492
|
return value;
|
|
3219
3493
|
}
|
|
3220
3494
|
// Lấy value ở option tag.
|
|
3221
3495
|
transformOptionValue(option) {
|
|
3222
|
-
const field = this.
|
|
3496
|
+
const field = this.field();
|
|
3223
3497
|
let optionValue;
|
|
3224
3498
|
optionValue = option[field.bindValue];
|
|
3225
3499
|
return optionValue;
|
|
@@ -3230,11 +3504,12 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3230
3504
|
}
|
|
3231
3505
|
// Biến đổi label nếu có thuộc tính hàm biến đổi transformLabel.
|
|
3232
3506
|
getCustomLabel(option) {
|
|
3233
|
-
const field = this.
|
|
3234
|
-
if (typeof option[field.bindLabel] ===
|
|
3235
|
-
|
|
3507
|
+
const field = this.field();
|
|
3508
|
+
if (typeof option[field.bindLabel] === "function" ||
|
|
3509
|
+
!option[field.bindLabel]) {
|
|
3510
|
+
let warnMessage = "Giá trị label lấy theo bindLabel hiện đang là dạng object, array hoặc các dạng còn lại của complex data";
|
|
3236
3511
|
if (!option[field.bindLabel])
|
|
3237
|
-
warnMessage =
|
|
3512
|
+
warnMessage = "Không tồn tại giá trị label khi lấy theo bindLabel";
|
|
3238
3513
|
// console.warn(warnMessage);
|
|
3239
3514
|
return NO_INFO_TEXT;
|
|
3240
3515
|
}
|
|
@@ -3253,62 +3528,55 @@ class TreeSelectComponent extends BaseValueAccessor {
|
|
|
3253
3528
|
useExisting: forwardRef(() => TreeSelectComponent),
|
|
3254
3529
|
multi: true,
|
|
3255
3530
|
},
|
|
3256
|
-
], usesInheritance: true, ngImport: i0, template: "<div class=\"d-flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
3531
|
+
], usesInheritance: true, ngImport: i0, template: "<div class=\"d-flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n <input nz-input [value]=\"displayValue\" class=\"modeView\" />\r\n }\r\n @if (viewMode() === viewModeEnum.text) {\r\n <span class=\"modeView break-work\">{{ displayValue }}</span>\r\n }\r\n } @else {\r\n <nz-tree-select\r\n [nzId]=\"fieldKey()\"\r\n nzShowSearch\r\n nzAllowClear\r\n [nzDisabled]=\"isDisabled\"\r\n [nzPlaceHolder]=\"displayPlaceholder()\"\r\n [title]=\"field().tooltip || ''\"\r\n [nzDropdownMatchSelectWidth]=\"field().matchSelectWidth\"\r\n [ngModel]=\"value\"\r\n [nzNodes]=\"options\"\r\n class=\"flex-1 min-w-0\"\r\n (ngModelChange)=\"handleChangeOptions($event)\"\r\n >\r\n </nz-tree-select>\r\n\r\n <ng-template #loadingIcon>\r\n <nz-spin nzSimple [nzSize]=\"'small'\"></nz-spin>\r\n </ng-template>\r\n }\r\n\r\n <!-- Suffixes -->\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\" [formId]=\"formId\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: i1.FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "ngmodule", type: NzTreeSelectModule }, { kind: "component", type: i2$1.NzTreeSelectComponent, selector: "nz-tree-select", inputs: ["nzId", "nzAllowClear", "nzShowExpand", "nzShowLine", "nzDropdownMatchSelectWidth", "nzCheckable", "nzHideUnMatched", "nzShowIcon", "nzShowSearch", "nzDisabled", "nzAsyncData", "nzMultiple", "nzDefaultExpandAll", "nzCheckStrictly", "nzVirtualItemSize", "nzVirtualMaxBufferPx", "nzVirtualMinBufferPx", "nzVirtualHeight", "nzExpandedIcon", "nzNotFoundContent", "nzNodes", "nzOpen", "nzSize", "nzPlaceHolder", "nzDropdownStyle", "nzDropdownClassName", "nzBackdrop", "nzStatus", "nzPlacement", "nzExpandedKeys", "nzDisplayWith", "nzMaxTagCount", "nzMaxTagPlaceholder", "nzTreeTemplate"], outputs: ["nzOpenChange", "nzCleared", "nzRemoved", "nzExpandChange", "nzTreeClick", "nzTreeCheckboxChange"], exportAs: ["nzTreeSelect"] }, { kind: "ngmodule", type: NzSpinModule }, { kind: "component", type: i3$2.NzSpinComponent, selector: "nz-spin", inputs: ["nzIndicator", "nzSize", "nzTip", "nzDelay", "nzSimple", "nzSpinning"], exportAs: ["nzSpin"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i1$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "component", type: SuffixComponent, selector: "app-suffix", inputs: ["suffixConfig", "formId"] }] }); }
|
|
3257
3532
|
}
|
|
3258
3533
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: TreeSelectComponent, decorators: [{
|
|
3259
3534
|
type: Component,
|
|
3260
|
-
args: [{ selector:
|
|
3535
|
+
args: [{ selector: "app-tree-select", standalone: true, imports: [...FORM_MODULES, ...ZORRO_MODULES$4, ...COMPONENTS$1], providers: [
|
|
3261
3536
|
{
|
|
3262
3537
|
provide: NG_VALUE_ACCESSOR,
|
|
3263
3538
|
useExisting: forwardRef(() => TreeSelectComponent),
|
|
3264
3539
|
multi: true,
|
|
3265
3540
|
},
|
|
3266
|
-
], template: "<div class=\"d-flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
3541
|
+
], template: "<div class=\"d-flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n <input nz-input [value]=\"displayValue\" class=\"modeView\" />\r\n }\r\n @if (viewMode() === viewModeEnum.text) {\r\n <span class=\"modeView break-work\">{{ displayValue }}</span>\r\n }\r\n } @else {\r\n <nz-tree-select\r\n [nzId]=\"fieldKey()\"\r\n nzShowSearch\r\n nzAllowClear\r\n [nzDisabled]=\"isDisabled\"\r\n [nzPlaceHolder]=\"displayPlaceholder()\"\r\n [title]=\"field().tooltip || ''\"\r\n [nzDropdownMatchSelectWidth]=\"field().matchSelectWidth\"\r\n [ngModel]=\"value\"\r\n [nzNodes]=\"options\"\r\n class=\"flex-1 min-w-0\"\r\n (ngModelChange)=\"handleChangeOptions($event)\"\r\n >\r\n </nz-tree-select>\r\n\r\n <ng-template #loadingIcon>\r\n <nz-spin nzSimple [nzSize]=\"'small'\"></nz-spin>\r\n </ng-template>\r\n }\r\n\r\n <!-- Suffixes -->\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\" [formId]=\"formId\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n" }]
|
|
3267
3542
|
}], ctorParameters: () => [], propDecorators: { isCustomInputText: [{
|
|
3268
3543
|
type: Input
|
|
3269
3544
|
}] } });
|
|
3270
3545
|
|
|
3271
|
-
const ZORRO_MODULES$
|
|
3546
|
+
const ZORRO_MODULES$3 = [NzInputModule];
|
|
3272
3547
|
class TextareaComponent extends BaseValueAccessor {
|
|
3273
3548
|
constructor() {
|
|
3274
3549
|
super();
|
|
3275
|
-
this.
|
|
3550
|
+
this.field = computed(() => {
|
|
3276
3551
|
const base = this.fieldInput();
|
|
3277
|
-
if (!(base instanceof TextareaField) ||
|
|
3278
|
-
|
|
3552
|
+
if (!(base instanceof TextareaField) ||
|
|
3553
|
+
base.type !== FieldTypeEnum.Textarea) {
|
|
3554
|
+
throw new Error("Expected TextareaField");
|
|
3279
3555
|
}
|
|
3280
3556
|
return base;
|
|
3281
3557
|
});
|
|
3282
|
-
this.textareaDisplayValue = '';
|
|
3283
3558
|
this.displayNoValueText = NO_INFO_TEXT;
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
if (this.
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
}
|
|
3292
|
-
});
|
|
3293
|
-
// Trigger reset từ bên ngoài form.
|
|
3294
|
-
effect(() => {
|
|
3295
|
-
const reset = this.dFormService.resetTrigger();
|
|
3296
|
-
if (reset?.formId === this.formId) {
|
|
3297
|
-
this.reset();
|
|
3298
|
-
}
|
|
3559
|
+
this.viewDisplayValue = computed(() => {
|
|
3560
|
+
// 1. Nếu không phải View thì không cần quan tâm text này
|
|
3561
|
+
if (!this.isView())
|
|
3562
|
+
return "";
|
|
3563
|
+
// 2. Lấy giá trị từ valueSignal
|
|
3564
|
+
const val = this.valueSignal();
|
|
3565
|
+
return val ? val : NO_INFO_TEXT;
|
|
3299
3566
|
});
|
|
3300
3567
|
}
|
|
3568
|
+
// Xử lý tạo placeholder text tự động nếu chưa truyền placeholder vào config của field
|
|
3569
|
+
resolvePlaceholderText() {
|
|
3570
|
+
return createInputPlaceholder(this.field());
|
|
3571
|
+
}
|
|
3301
3572
|
handleChangeTextarea(event) {
|
|
3302
3573
|
const textareaValue = event.target.value;
|
|
3303
3574
|
this.propagateValue(textareaValue);
|
|
3304
3575
|
// Gán data vào đầu ra của form.
|
|
3305
|
-
this.patchFormData(this.fieldKey(), textareaValue &&
|
|
3576
|
+
this.patchFormData(this.fieldKey(), textareaValue &&
|
|
3577
|
+
textareaValue.replace(/\n+/g, "br_enter").replace(/br_enter+/g, "\n"));
|
|
3306
3578
|
}
|
|
3307
3579
|
writeValueToView(value) {
|
|
3308
|
-
if (this.isView()) {
|
|
3309
|
-
this.textareaDisplayValue = this.fieldSignal().modelValue || NO_INFO_TEXT;
|
|
3310
|
-
return;
|
|
3311
|
-
}
|
|
3312
3580
|
if (!this.isAddOrEdit())
|
|
3313
3581
|
return;
|
|
3314
3582
|
// Gán data vào đầu ra của form.
|
|
@@ -3321,17 +3589,17 @@ class TextareaComponent extends BaseValueAccessor {
|
|
|
3321
3589
|
useExisting: forwardRef(() => TextareaComponent),
|
|
3322
3590
|
multi: true,
|
|
3323
3591
|
},
|
|
3324
|
-
], usesInheritance: true, ngImport: i0, template: "@if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
3592
|
+
], usesInheritance: true, ngImport: i0, template: "@if (modeSignal() === formModeEnum.View) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n @if (viewDisplayValue(); as displayValue) {\r\n <p\r\n [innerHTML]=\"displayValue\"\r\n class=\"disabled-textarea break-work mb0\"\r\n ></p>\r\n } @else {\r\n <input nz-input [value]=\"displayNoValueText\" class=\"modeView\" />\r\n }\r\n }\r\n @if (viewMode() === viewModeEnum.text) {\r\n @if (viewDisplayValue(); as displayValue) {\r\n <p [innerHTML]=\"displayValue\" class=\"mode-view mb-0 break-work mb0\"></p>\r\n } @else {\r\n <span class=\"modeView\">{{ displayNoValueText }}</span>\r\n }\r\n }\r\n} @else {\r\n <textarea\r\n nz-input\r\n [nzAutosize]=\"{ minRows: 1, maxRows: 8 }\"\r\n [value]=\"value\"\r\n [disabled]=\"isDisabled\"\r\n [placeholder]=\"displayPlaceholder()\"\r\n (input)=\"handleChangeTextarea($event)\"\r\n >\r\n </textarea>\r\n}\r\n", styles: [".disabled-textarea{padding:4px 8px;border:1px solid #cbd5e1;color:#575757!important;cursor:not-allowed;pointer-events:none}.mode-view{pointer-events:none;color:#575757;font-size:12px}\n"], dependencies: [{ kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i1$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "directive", type: i1$1.NzAutosizeDirective, selector: "textarea[nzAutosize]", inputs: ["nzAutosize"], exportAs: ["nzAutosize"] }] }); }
|
|
3325
3593
|
}
|
|
3326
3594
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: TextareaComponent, decorators: [{
|
|
3327
3595
|
type: Component,
|
|
3328
|
-
args: [{ selector:
|
|
3596
|
+
args: [{ selector: "app-textarea", standalone: true, imports: [...ZORRO_MODULES$3], providers: [
|
|
3329
3597
|
{
|
|
3330
3598
|
provide: NG_VALUE_ACCESSOR,
|
|
3331
3599
|
useExisting: forwardRef(() => TextareaComponent),
|
|
3332
3600
|
multi: true,
|
|
3333
3601
|
},
|
|
3334
|
-
], template: "@if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
3602
|
+
], template: "@if (modeSignal() === formModeEnum.View) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n @if (viewDisplayValue(); as displayValue) {\r\n <p\r\n [innerHTML]=\"displayValue\"\r\n class=\"disabled-textarea break-work mb0\"\r\n ></p>\r\n } @else {\r\n <input nz-input [value]=\"displayNoValueText\" class=\"modeView\" />\r\n }\r\n }\r\n @if (viewMode() === viewModeEnum.text) {\r\n @if (viewDisplayValue(); as displayValue) {\r\n <p [innerHTML]=\"displayValue\" class=\"mode-view mb-0 break-work mb0\"></p>\r\n } @else {\r\n <span class=\"modeView\">{{ displayNoValueText }}</span>\r\n }\r\n }\r\n} @else {\r\n <textarea\r\n nz-input\r\n [nzAutosize]=\"{ minRows: 1, maxRows: 8 }\"\r\n [value]=\"value\"\r\n [disabled]=\"isDisabled\"\r\n [placeholder]=\"displayPlaceholder()\"\r\n (input)=\"handleChangeTextarea($event)\"\r\n >\r\n </textarea>\r\n}\r\n", styles: [".disabled-textarea{padding:4px 8px;border:1px solid #cbd5e1;color:#575757!important;cursor:not-allowed;pointer-events:none}.mode-view{pointer-events:none;color:#575757;font-size:12px}\n"] }]
|
|
3335
3603
|
}], ctorParameters: () => [] });
|
|
3336
3604
|
|
|
3337
3605
|
class FileService {
|
|
@@ -3372,31 +3640,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
3372
3640
|
}]
|
|
3373
3641
|
}] });
|
|
3374
3642
|
|
|
3375
|
-
const
|
|
3643
|
+
const modules$2 = [CommonModule];
|
|
3644
|
+
const zorroModules$2 = [NzUploadModule, NzIconModule];
|
|
3376
3645
|
class AvatarUploadComponent extends BaseValueAccessor {
|
|
3377
3646
|
constructor() {
|
|
3378
3647
|
super();
|
|
3379
3648
|
this.size = 100; // kích thước avatar
|
|
3380
|
-
this.
|
|
3649
|
+
this.field = computed(() => {
|
|
3381
3650
|
const base = this.fieldInput();
|
|
3382
3651
|
if (!(base instanceof AvatarUploadField) ||
|
|
3383
|
-
(base.type !== FieldTypeEnum.AvatarUpload &&
|
|
3384
|
-
|
|
3652
|
+
(base.type !== FieldTypeEnum.AvatarUpload &&
|
|
3653
|
+
base.controlType !== ControlTypeEnum.Upload)) {
|
|
3654
|
+
throw new Error("Expected AvatarUploadField");
|
|
3385
3655
|
}
|
|
3386
3656
|
return base;
|
|
3387
3657
|
});
|
|
3388
|
-
|
|
3389
|
-
// Mảng lưu trữ objectStorage liên quan đến tập tin.
|
|
3390
|
-
this.objStorageList = signal([]);
|
|
3658
|
+
// Inject services
|
|
3391
3659
|
this.fileService = inject(FileService);
|
|
3392
3660
|
this.formConfigService = inject(FormConfigService);
|
|
3393
3661
|
this.nzNotification = inject(NzNotificationService);
|
|
3662
|
+
this.avatarUrl = signal(null);
|
|
3663
|
+
this.uploading = signal(false);
|
|
3664
|
+
// Mảng lưu trữ objectStorage liên quan đến tập tin.
|
|
3665
|
+
this.objStorageList = signal([]);
|
|
3394
3666
|
this.beforeUpload = (file, fileList) => {
|
|
3395
3667
|
// const originFile = file?.originFileObj as unknown as File; // có thể ở version mới nhất đã fix lỗi NzUploadFile nhưng trả về File của tham số file.
|
|
3396
3668
|
// Xử lý gán vào CVA để tiến hành validation theo các props đã truyền vào.
|
|
3397
3669
|
const originFile = file;
|
|
3398
3670
|
this.propagateValue(originFile);
|
|
3399
|
-
const { maxSizeInMB, acceptedMimeTypes } = this.
|
|
3671
|
+
const { maxSizeInMB, acceptedMimeTypes } = this.field();
|
|
3400
3672
|
const fileSizeInMB = formatFileSize(file.size, FileSizeTypeEnum.MB);
|
|
3401
3673
|
const fileType = file.type;
|
|
3402
3674
|
if (fileSizeInMB > maxSizeInMB || !acceptedMimeTypes.includes(fileType)) {
|
|
@@ -3414,13 +3686,6 @@ class AvatarUploadComponent extends BaseValueAccessor {
|
|
|
3414
3686
|
// Validation đã thỏa, tiến hành upload file.
|
|
3415
3687
|
return this.uploadFile(originFile);
|
|
3416
3688
|
};
|
|
3417
|
-
// Trigger reset từ bên ngoài form.
|
|
3418
|
-
effect(() => {
|
|
3419
|
-
const reset = this.dFormService.resetTrigger();
|
|
3420
|
-
if (reset?.formId === this.formId) {
|
|
3421
|
-
this.reset();
|
|
3422
|
-
}
|
|
3423
|
-
});
|
|
3424
3689
|
}
|
|
3425
3690
|
// Chạy khi value form được gán bởi các hàm reset, patchValue, setValue.
|
|
3426
3691
|
writeValueToView(value) {
|
|
@@ -3435,31 +3700,33 @@ class AvatarUploadComponent extends BaseValueAccessor {
|
|
|
3435
3700
|
handleInitAllData(value) {
|
|
3436
3701
|
// Reset khi đổi mode, hoặc model, hoặc fields.
|
|
3437
3702
|
this.objStorageList.set([]);
|
|
3438
|
-
this.avatarUrl
|
|
3703
|
+
this.avatarUrl.set(null);
|
|
3439
3704
|
if (isValidJSON(value)) {
|
|
3440
3705
|
const objStorageList = JSON.parse(value);
|
|
3441
3706
|
this.objStorageList.set(objStorageList);
|
|
3442
|
-
this.avatarUrl
|
|
3707
|
+
this.avatarUrl.set(this.formConfigService.getViewFileUrl(objStorageList[0]?.name ?? "", false));
|
|
3443
3708
|
}
|
|
3444
3709
|
}
|
|
3445
3710
|
uploadFile(file) {
|
|
3446
|
-
|
|
3447
|
-
const
|
|
3711
|
+
this.uploading.set(true);
|
|
3712
|
+
const { uploadTemp } = this.field();
|
|
3713
|
+
const newFileName = this.formConfigService.generateRandomFileName(file.name, "avatar");
|
|
3448
3714
|
const renamedFile = new File([file], newFileName, { type: file.type });
|
|
3449
3715
|
const formData = new FormData();
|
|
3450
|
-
formData.append(
|
|
3451
|
-
// formData.append('isTemp', 'true');
|
|
3716
|
+
formData.append("File", renamedFile);
|
|
3452
3717
|
if (uploadTemp)
|
|
3453
|
-
formData.append(
|
|
3718
|
+
formData.append("isTemp", "true");
|
|
3454
3719
|
return this.fileService
|
|
3455
|
-
.uploadFile(renamedFile, formData, {
|
|
3456
|
-
|
|
3720
|
+
.uploadFile(renamedFile, formData, {
|
|
3721
|
+
uploadUrl: this.field().apiFileConfig.uploadUrl,
|
|
3722
|
+
})
|
|
3723
|
+
.pipe(this.takeUntilDestroy(), finalize(() => this.uploading.set(false)))
|
|
3457
3724
|
.subscribe({
|
|
3458
|
-
next: res => {
|
|
3725
|
+
next: (res) => {
|
|
3459
3726
|
const { code, data, message } = res;
|
|
3460
3727
|
if (code === 0) {
|
|
3461
3728
|
this.objStorageList.set([data]);
|
|
3462
|
-
this.avatarUrl
|
|
3729
|
+
this.avatarUrl.set(this.formConfigService.getViewFileUrl(data?.name ?? "", true));
|
|
3463
3730
|
this.patchFormData(this.fieldKey(), JSON.stringify(this.objStorageList()));
|
|
3464
3731
|
}
|
|
3465
3732
|
else {
|
|
@@ -3467,21 +3734,18 @@ class AvatarUploadComponent extends BaseValueAccessor {
|
|
|
3467
3734
|
}
|
|
3468
3735
|
},
|
|
3469
3736
|
error: () => {
|
|
3470
|
-
console.error(
|
|
3737
|
+
console.error(UPLOAD_FILE_ERROR);
|
|
3471
3738
|
},
|
|
3472
3739
|
});
|
|
3473
3740
|
}
|
|
3474
|
-
handleDelete(file) {
|
|
3475
|
-
this.objStorageList.set([]);
|
|
3476
|
-
this.patchFormData(this.fieldKey(), JSON.stringify(this.objStorageList()));
|
|
3477
|
-
}
|
|
3478
|
-
handlePreview() { }
|
|
3479
3741
|
deleteObjStorage(id) {
|
|
3480
3742
|
return this.fileService
|
|
3481
|
-
.deleteObjStorage(id, {
|
|
3743
|
+
.deleteObjStorage(id, {
|
|
3744
|
+
deleteUrl: this.field().apiFileConfig.deleteUrl,
|
|
3745
|
+
})
|
|
3482
3746
|
.pipe(this.takeUntilDestroy())
|
|
3483
3747
|
.subscribe({
|
|
3484
|
-
next: res => {
|
|
3748
|
+
next: (res) => {
|
|
3485
3749
|
const { code, message } = res;
|
|
3486
3750
|
if (code === 0) {
|
|
3487
3751
|
this.objStorageList.set([]);
|
|
@@ -3492,7 +3756,7 @@ class AvatarUploadComponent extends BaseValueAccessor {
|
|
|
3492
3756
|
}
|
|
3493
3757
|
},
|
|
3494
3758
|
error: (err) => {
|
|
3495
|
-
console.error(
|
|
3759
|
+
console.error(DELETE_FILE_ERROR);
|
|
3496
3760
|
// Tạm do api xóa có vấn đề
|
|
3497
3761
|
this.objStorageList.set([]);
|
|
3498
3762
|
this.patchFormData(this.fieldKey(), JSON.stringify(this.objStorageList()));
|
|
@@ -3506,27 +3770,27 @@ class AvatarUploadComponent extends BaseValueAccessor {
|
|
|
3506
3770
|
useExisting: forwardRef(() => AvatarUploadComponent),
|
|
3507
3771
|
multi: true,
|
|
3508
3772
|
},
|
|
3509
|
-
], usesInheritance: true, ngImport: i0, template: "<nz-upload\r\n [nzDisabled]=\"
|
|
3773
|
+
], usesInheritance: true, ngImport: i0, template: "<nz-upload\r\n [nzDisabled]=\"disabledSignal() || isView()\"\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"false\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n>\r\n <ng-container *ngTemplateOutlet=\"renderAvatarTpl\"></ng-container>\r\n</nz-upload>\r\n\r\n<!-- Template custom hi\u1EC3n th\u1ECB avatar -->\r\n<ng-template #renderAvatarTpl>\r\n <div\r\n class=\"avatar-wrapper\"\r\n [ngStyle]=\"{ width: size + 'px', height: size + 'px' }\"\r\n >\r\n @if (uploading()) {\r\n <span\r\n nz-icon\r\n nzType=\"loading\"\r\n nzTheme=\"outline\"\r\n class=\"upload-icon\"\r\n ></span>\r\n } @else if (!avatarUrl() && isAddOrEdit()) {\r\n <span nz-icon nzType=\"plus\" nzTheme=\"outline\" class=\"upload-icon\"></span>\r\n } @else if (avatarUrl()) {\r\n <img [src]=\"avatarUrl()\" alt=\"\" class=\"avatar-img\" />\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: [".avatar-wrapper{display:flex;align-items:center;justify-content:center;border:1px dashed #d9d9d9;border-radius:8px;background-color:#fafafa;cursor:pointer;overflow:hidden}.avatar-wrapper .upload-icon{font-size:24px;color:#999}.avatar-wrapper .avatar-img{width:100%;height:100%;object-fit:cover}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: NzUploadModule }, { kind: "component", type: i2$2.NzUploadComponent, selector: "nz-upload", inputs: ["nzType", "nzLimit", "nzSize", "nzFileType", "nzAccept", "nzAction", "nzDirectory", "nzOpenFileDialogOnClick", "nzBeforeUpload", "nzCustomRequest", "nzData", "nzFilter", "nzFileList", "nzDisabled", "nzHeaders", "nzListType", "nzMultiple", "nzName", "nzShowUploadList", "nzShowButton", "nzWithCredentials", "nzRemove", "nzPreview", "nzPreviewFile", "nzPreviewIsImage", "nzTransformFile", "nzDownload", "nzIconRender", "nzFileListRender"], outputs: ["nzChange", "nzFileListChange"], exportAs: ["nzUpload"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }] }); }
|
|
3510
3774
|
}
|
|
3511
3775
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: AvatarUploadComponent, decorators: [{
|
|
3512
3776
|
type: Component,
|
|
3513
|
-
args: [{ selector:
|
|
3777
|
+
args: [{ selector: "app-avatar-upload", standalone: true, imports: [...modules$2, ...zorroModules$2], providers: [
|
|
3514
3778
|
{
|
|
3515
3779
|
provide: NG_VALUE_ACCESSOR,
|
|
3516
3780
|
useExisting: forwardRef(() => AvatarUploadComponent),
|
|
3517
3781
|
multi: true,
|
|
3518
3782
|
},
|
|
3519
|
-
], template: "<nz-upload\r\n [nzDisabled]=\"
|
|
3783
|
+
], template: "<nz-upload\r\n [nzDisabled]=\"disabledSignal() || isView()\"\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"false\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n>\r\n <ng-container *ngTemplateOutlet=\"renderAvatarTpl\"></ng-container>\r\n</nz-upload>\r\n\r\n<!-- Template custom hi\u1EC3n th\u1ECB avatar -->\r\n<ng-template #renderAvatarTpl>\r\n <div\r\n class=\"avatar-wrapper\"\r\n [ngStyle]=\"{ width: size + 'px', height: size + 'px' }\"\r\n >\r\n @if (uploading()) {\r\n <span\r\n nz-icon\r\n nzType=\"loading\"\r\n nzTheme=\"outline\"\r\n class=\"upload-icon\"\r\n ></span>\r\n } @else if (!avatarUrl() && isAddOrEdit()) {\r\n <span nz-icon nzType=\"plus\" nzTheme=\"outline\" class=\"upload-icon\"></span>\r\n } @else if (avatarUrl()) {\r\n <img [src]=\"avatarUrl()\" alt=\"\" class=\"avatar-img\" />\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: [".avatar-wrapper{display:flex;align-items:center;justify-content:center;border:1px dashed #d9d9d9;border-radius:8px;background-color:#fafafa;cursor:pointer;overflow:hidden}.avatar-wrapper .upload-icon{font-size:24px;color:#999}.avatar-wrapper .avatar-img{width:100%;height:100%;object-fit:cover}\n"] }]
|
|
3520
3784
|
}], ctorParameters: () => [], propDecorators: { size: [{
|
|
3521
3785
|
type: Input
|
|
3522
3786
|
}] } });
|
|
3523
3787
|
|
|
3524
|
-
const ZORRO_MODULES$
|
|
3788
|
+
const ZORRO_MODULES$2 = [NzUploadModule, NzIconModule, NzButtonModule];
|
|
3525
3789
|
class MultiFileUploadComponent extends BaseValueAccessor {
|
|
3526
3790
|
constructor() {
|
|
3527
3791
|
super();
|
|
3528
3792
|
// Cast lại đúng instance là MultiFileUploadFile.
|
|
3529
|
-
this.
|
|
3793
|
+
this.field = computed(() => {
|
|
3530
3794
|
const base = this.fieldInput();
|
|
3531
3795
|
if (!(base instanceof MultiFileUploadField) ||
|
|
3532
3796
|
(base.type !== FieldTypeEnum.MultiFileUpload &&
|
|
@@ -3540,7 +3804,12 @@ class MultiFileUploadComponent extends BaseValueAccessor {
|
|
|
3540
3804
|
// Mảng đại diện các images.
|
|
3541
3805
|
this.allFiles = signal([]);
|
|
3542
3806
|
// Text hướng dẫn các loại extension được upload.
|
|
3543
|
-
this.fileExtensionGuide =
|
|
3807
|
+
this.fileExtensionGuide = computed(() => {
|
|
3808
|
+
if (!this.isAddOrEdit())
|
|
3809
|
+
return "";
|
|
3810
|
+
const { acceptedMimeTypes } = this.field();
|
|
3811
|
+
return `Hỗ trợ định dạng ${getExtensions(acceptedMimeTypes).join(", ")}`;
|
|
3812
|
+
});
|
|
3544
3813
|
// Đếm số file đã pass beforeUpload nhưng chưa upload xong (đang trong hàng chờ customRequest/uploadFile).
|
|
3545
3814
|
// Dùng để tính toán count chính xác khi user chọn nhiều file cùng lúc.
|
|
3546
3815
|
this.pendingCount = signal(0);
|
|
@@ -3549,8 +3818,6 @@ class MultiFileUploadComponent extends BaseValueAccessor {
|
|
|
3549
3818
|
// Timer dùng để phát hiện kết thúc một batch (setTimeout(0)).
|
|
3550
3819
|
this._batchTimer = null;
|
|
3551
3820
|
this.fileService = inject(FileService);
|
|
3552
|
-
this.toast = inject(ToastrService);
|
|
3553
|
-
this.translate = inject(TranslateService);
|
|
3554
3821
|
this.nzMessage = inject(NzMessageService);
|
|
3555
3822
|
this.nzNotification = inject(NzNotificationService);
|
|
3556
3823
|
this.formConfigService = inject(FormConfigService);
|
|
@@ -3593,22 +3860,6 @@ class MultiFileUploadComponent extends BaseValueAccessor {
|
|
|
3593
3860
|
// Validation đã thỏa, tiến hành upload file.
|
|
3594
3861
|
return this.uploadFile(originFile, uid);
|
|
3595
3862
|
};
|
|
3596
|
-
// 1. Effect chung Add + Edit
|
|
3597
|
-
effect(() => {
|
|
3598
|
-
if (this.isAddOrEdit()) {
|
|
3599
|
-
const field = untracked(() => this.fieldSignal());
|
|
3600
|
-
const { acceptedMimeTypes } = field;
|
|
3601
|
-
this.fileExtensionGuide.set(`Hỗ trợ các định dạng ${getExtensions(acceptedMimeTypes).join(", ")}`);
|
|
3602
|
-
}
|
|
3603
|
-
});
|
|
3604
|
-
// Trigger reset từ bên ngoài form.
|
|
3605
|
-
effect(() => {
|
|
3606
|
-
const reset = this.dFormService.resetTrigger();
|
|
3607
|
-
if (reset?.formId === this.formId) {
|
|
3608
|
-
this._clearBatch(); // Hủy batch đang xử lý trước khi reset.
|
|
3609
|
-
this.reset();
|
|
3610
|
-
}
|
|
3611
|
-
});
|
|
3612
3863
|
}
|
|
3613
3864
|
// Chạy khi value form được gán bởi các hàm reset, patchValue, setValue.
|
|
3614
3865
|
writeValueToView(value) {
|
|
@@ -3652,16 +3903,11 @@ class MultiFileUploadComponent extends BaseValueAccessor {
|
|
|
3652
3903
|
const batch = [...this._batchBuffer];
|
|
3653
3904
|
this._batchBuffer = [];
|
|
3654
3905
|
this._batchTimer = null;
|
|
3655
|
-
const { maxFileCount, maxSizeInMB, acceptedMimeTypes } = this.
|
|
3906
|
+
const { maxFileCount, maxSizeInMB, acceptedMimeTypes } = this.field();
|
|
3656
3907
|
// Số file hiện tại: đã upload xong + đang trong hàng chờ upload.
|
|
3657
3908
|
const currentCount = this.allFiles().length + this.pendingCount();
|
|
3658
3909
|
// ── CHECK 1: Tổng batch vượt maxFileCount → reject TOÀN BỘ batch ──
|
|
3659
3910
|
if (currentCount + batch.length > maxFileCount) {
|
|
3660
|
-
// this.toast.warning(
|
|
3661
|
-
// this.translate.instant(
|
|
3662
|
-
// `Không thể tải lên: số lượng file chọn (${batch.length}) vượt quá giới hạn cho phép. Tối đa ${maxFileCount} tập tin.`,
|
|
3663
|
-
// ),
|
|
3664
|
-
// );
|
|
3665
3911
|
this.nzNotification.warning("Cảnh báo", `Không thể tải lên: số lượng file tải lên vượt quá giới hạn cho phép. Tối đa ${maxFileCount} tập tin.`, { nzDuration: 4500 });
|
|
3666
3912
|
batch.forEach(({ resolve }) => resolve(false));
|
|
3667
3913
|
return;
|
|
@@ -3706,7 +3952,7 @@ class MultiFileUploadComponent extends BaseValueAccessor {
|
|
|
3706
3952
|
}
|
|
3707
3953
|
}
|
|
3708
3954
|
uploadFile(file, uid) {
|
|
3709
|
-
const { apiFileConfig, uploadTemp } = this.
|
|
3955
|
+
const { apiFileConfig, uploadTemp } = this.field();
|
|
3710
3956
|
const newFileName = this.formConfigService.generateRandomFileName(file.name, "file");
|
|
3711
3957
|
const renamedFile = new File([file], newFileName, { type: file.type });
|
|
3712
3958
|
const mimeCfg = apiFileConfig.perMimeTypeConfig?.[file.type]; // Lấy mimeTypes file upload.
|
|
@@ -3771,7 +4017,7 @@ class MultiFileUploadComponent extends BaseValueAccessor {
|
|
|
3771
4017
|
}
|
|
3772
4018
|
handleDelete(file) {
|
|
3773
4019
|
const { objStorage, uploadStatus } = file;
|
|
3774
|
-
const { uploadTemp } = this.
|
|
4020
|
+
const { uploadTemp } = this.field();
|
|
3775
4021
|
// Loại bỏ và cập nhật danh sách ObjectStorage.
|
|
3776
4022
|
const newObjStorageList = this.objStorageList().filter((item) => item.id !== objStorage?.id);
|
|
3777
4023
|
this.objStorageList.set(newObjStorageList);
|
|
@@ -3797,7 +4043,7 @@ class MultiFileUploadComponent extends BaseValueAccessor {
|
|
|
3797
4043
|
deleteObjStorage(id) {
|
|
3798
4044
|
return this.fileService
|
|
3799
4045
|
.deleteObjStorage(id, {
|
|
3800
|
-
deleteUrl: this.
|
|
4046
|
+
deleteUrl: this.field().apiFileConfig.deleteUrl,
|
|
3801
4047
|
})
|
|
3802
4048
|
.pipe(this.takeUntilDestroy())
|
|
3803
4049
|
.subscribe({
|
|
@@ -3878,29 +4124,35 @@ class MultiFileUploadComponent extends BaseValueAccessor {
|
|
|
3878
4124
|
useExisting: forwardRef(() => MultiFileUploadComponent),
|
|
3879
4125
|
multi: true,
|
|
3880
4126
|
},
|
|
3881
|
-
], usesInheritance: true, ngImport: i0, template: "@if (isAddOrEdit()) {\r\n <nz-upload\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"true\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n >\r\n <button nz-button class=\"btn-upload\" nzType=\"primary\" nzSize=\"small\">\r\n <nz-icon nzType=\"upload\" nzTheme=\"outline\" />\r\n <span class=\"font-size-12\">T\u1EA3i l\u00EAn</span>\r\n </button>\r\n\r\n <span class=\"font-size-12\"\r\n >( T\u1ED1i \u0111a {{
|
|
4127
|
+
], usesInheritance: true, ngImport: i0, template: "@if (isAddOrEdit()) {\r\n <nz-upload\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"true\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n >\r\n <button nz-button class=\"btn-upload\" nzType=\"primary\" nzSize=\"small\">\r\n <nz-icon nzType=\"upload\" nzTheme=\"outline\" />\r\n <span class=\"font-size-12\">T\u1EA3i l\u00EAn</span>\r\n </button>\r\n\r\n <span class=\"font-size-12\"\r\n >( T\u1ED1i \u0111a {{ field().maxFileCount }} t\u1EADp tin )</span\r\n >\r\n\r\n @if (field().showAcceptedExtensionGuide) {\r\n <div class=\"file-extension-guide\">{{ fileExtensionGuide() }}</div>\r\n }\r\n </nz-upload>\r\n}\r\n\r\n<!-- Custom hi\u1EC3n th\u1ECB danh s\u00E1ch t\u1EADp tin -->\r\n@if (allFiles().length > 0) {\r\n <ng-container *ngTemplateOutlet=\"renderFileTpl\"></ng-container>\r\n} @else {\r\n @if (isView()) {\r\n <span class=\"no-text-info\">Kh\u00F4ng c\u00F3 th\u00F4ng tin</span>\r\n }\r\n}\r\n\r\n<!-- Template custom hi\u1EC3n th\u1ECB danh s\u00E1ch t\u1EADp tin -->\r\n<ng-template #renderFileTpl>\r\n <ul class=\"custom-upload-list\">\r\n @for (file of allFiles(); track file.objStorage?.id) {\r\n <li\r\n class=\"upload-item\"\r\n [class.is-loading]=\"file.uploadStatus === 'loading'\"\r\n [class.is-error]=\"file.uploadStatus === 'error'\"\r\n (click)=\"onFileItemClick(file)\"\r\n >\r\n <!-- Icon tr\u1EA1ng th\u00E1i b\u00EAn tr\u00E1i -->\r\n @switch (file.uploadStatus) {\r\n @case (\"loading\") {\r\n <span\r\n nz-icon\r\n nzType=\"loading\"\r\n nzTheme=\"outline\"\r\n class=\"status-icon loading-icon\"\r\n ></span>\r\n }\r\n @case (\"error\") {\r\n <span\r\n nz-icon\r\n nzType=\"close-circle\"\r\n nzTheme=\"fill\"\r\n class=\"status-icon error-icon\"\r\n ></span>\r\n }\r\n @default {\r\n <span\r\n nz-icon\r\n nzType=\"paper-clip\"\r\n nzTheme=\"outline\"\r\n class=\"paper-clip-icon\"\r\n ></span>\r\n }\r\n }\r\n\r\n <span class=\"file-name\" [title]=\"file.objStorage.name ?? ''\">{{\r\n file.objStorage.name\r\n }}</span>\r\n\r\n @if (isAddOrEdit() && file.uploadStatus !== \"loading\") {\r\n <span\r\n nz-icon\r\n nzType=\"delete\"\r\n nzTheme=\"outline\"\r\n title=\"X\u00F3a\"\r\n class=\"delete-icon\"\r\n (click)=\"handleDelete(file); $event.stopPropagation()\"\r\n ></span>\r\n }\r\n\r\n @if (\r\n !isAddOrEdit() &&\r\n file.uploadStatus !== \"error\" &&\r\n file.uploadStatus !== \"loading\"\r\n ) {\r\n <span\r\n nz-icon\r\n nzType=\"eye\"\r\n nzTheme=\"outline\"\r\n class=\"view-icon\"\r\n title=\"Xem file\"\r\n ></span>\r\n }\r\n </li>\r\n }\r\n </ul>\r\n</ng-template>\r\n", styles: [".upload{display:flex}nz-upload .btn-upload{margin-right:.75rem}nz-upload .file-extension-guide{font-size:11px;margin-top:8px;font-style:italic;color:#0f766e}.no-text-info{pointer-events:none;background-color:#fff;color:#575757!important}.custom-upload-list{margin-top:.625rem;list-style-type:none;padding-inline-start:10px}.custom-upload-list .upload-item{margin-bottom:.25rem;display:flex;align-items:center;max-width:100%;gap:.5rem;cursor:pointer;border-radius:4px;transition:background-color .15s ease}.custom-upload-list .upload-item .paper-clip-icon{margin-right:.5rem;color:#595959;flex-shrink:0}.custom-upload-list .upload-item .status-icon{flex-shrink:0}.custom-upload-list .upload-item .loading-icon{color:#1677ff}.custom-upload-list .upload-item .error-icon{color:#ff4d4f}.custom-upload-list .upload-item .file-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.custom-upload-list .upload-item .file-name:hover{text-decoration:underline;color:#0a4c9f;cursor:pointer}.custom-upload-list .upload-item .delete-icon{color:red;cursor:pointer;flex-shrink:0}.custom-upload-list .upload-item .view-icon{color:#1677ff;flex-shrink:0;opacity:.6;transition:opacity .15s ease}.custom-upload-list .upload-item:hover .view-icon{opacity:1}.custom-upload-list .upload-item.is-loading{cursor:default;opacity:.75}.custom-upload-list .upload-item.is-loading .file-name:hover{text-decoration:none;color:inherit;cursor:default}.custom-upload-list .upload-item.is-error{cursor:default}.custom-upload-list .upload-item.is-error .file-name{color:#ff4d4f}.custom-upload-list .upload-item.is-error .file-name:hover{text-decoration:none;color:#ff4d4f;cursor:default}\n"], dependencies: [{ kind: "ngmodule", type: i1$2.CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: NzUploadModule }, { kind: "component", type: i2$2.NzUploadComponent, selector: "nz-upload", inputs: ["nzType", "nzLimit", "nzSize", "nzFileType", "nzAccept", "nzAction", "nzDirectory", "nzOpenFileDialogOnClick", "nzBeforeUpload", "nzCustomRequest", "nzData", "nzFilter", "nzFileList", "nzDisabled", "nzHeaders", "nzListType", "nzMultiple", "nzName", "nzShowUploadList", "nzShowButton", "nzWithCredentials", "nzRemove", "nzPreview", "nzPreviewFile", "nzPreviewIsImage", "nzTransformFile", "nzDownload", "nzIconRender", "nzFileListRender"], outputs: ["nzChange", "nzFileListChange"], exportAs: ["nzUpload"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i4.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i5.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i6.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }] }); }
|
|
3882
4128
|
}
|
|
3883
4129
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MultiFileUploadComponent, decorators: [{
|
|
3884
4130
|
type: Component,
|
|
3885
|
-
args: [{ selector: "app-multi-file-upload", standalone: true, imports: [...CORE_MODULES, ...ZORRO_MODULES$
|
|
4131
|
+
args: [{ selector: "app-multi-file-upload", standalone: true, imports: [...CORE_MODULES, ...ZORRO_MODULES$2], providers: [
|
|
3886
4132
|
{
|
|
3887
4133
|
provide: NG_VALUE_ACCESSOR,
|
|
3888
4134
|
useExisting: forwardRef(() => MultiFileUploadComponent),
|
|
3889
4135
|
multi: true,
|
|
3890
4136
|
},
|
|
3891
|
-
], template: "@if (isAddOrEdit()) {\r\n <nz-upload\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"true\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n >\r\n <button nz-button class=\"btn-upload\" nzType=\"primary\" nzSize=\"small\">\r\n <nz-icon nzType=\"upload\" nzTheme=\"outline\" />\r\n <span class=\"font-size-12\">T\u1EA3i l\u00EAn</span>\r\n </button>\r\n\r\n <span class=\"font-size-12\"\r\n >( T\u1ED1i \u0111a {{
|
|
4137
|
+
], template: "@if (isAddOrEdit()) {\r\n <nz-upload\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"true\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n >\r\n <button nz-button class=\"btn-upload\" nzType=\"primary\" nzSize=\"small\">\r\n <nz-icon nzType=\"upload\" nzTheme=\"outline\" />\r\n <span class=\"font-size-12\">T\u1EA3i l\u00EAn</span>\r\n </button>\r\n\r\n <span class=\"font-size-12\"\r\n >( T\u1ED1i \u0111a {{ field().maxFileCount }} t\u1EADp tin )</span\r\n >\r\n\r\n @if (field().showAcceptedExtensionGuide) {\r\n <div class=\"file-extension-guide\">{{ fileExtensionGuide() }}</div>\r\n }\r\n </nz-upload>\r\n}\r\n\r\n<!-- Custom hi\u1EC3n th\u1ECB danh s\u00E1ch t\u1EADp tin -->\r\n@if (allFiles().length > 0) {\r\n <ng-container *ngTemplateOutlet=\"renderFileTpl\"></ng-container>\r\n} @else {\r\n @if (isView()) {\r\n <span class=\"no-text-info\">Kh\u00F4ng c\u00F3 th\u00F4ng tin</span>\r\n }\r\n}\r\n\r\n<!-- Template custom hi\u1EC3n th\u1ECB danh s\u00E1ch t\u1EADp tin -->\r\n<ng-template #renderFileTpl>\r\n <ul class=\"custom-upload-list\">\r\n @for (file of allFiles(); track file.objStorage?.id) {\r\n <li\r\n class=\"upload-item\"\r\n [class.is-loading]=\"file.uploadStatus === 'loading'\"\r\n [class.is-error]=\"file.uploadStatus === 'error'\"\r\n (click)=\"onFileItemClick(file)\"\r\n >\r\n <!-- Icon tr\u1EA1ng th\u00E1i b\u00EAn tr\u00E1i -->\r\n @switch (file.uploadStatus) {\r\n @case (\"loading\") {\r\n <span\r\n nz-icon\r\n nzType=\"loading\"\r\n nzTheme=\"outline\"\r\n class=\"status-icon loading-icon\"\r\n ></span>\r\n }\r\n @case (\"error\") {\r\n <span\r\n nz-icon\r\n nzType=\"close-circle\"\r\n nzTheme=\"fill\"\r\n class=\"status-icon error-icon\"\r\n ></span>\r\n }\r\n @default {\r\n <span\r\n nz-icon\r\n nzType=\"paper-clip\"\r\n nzTheme=\"outline\"\r\n class=\"paper-clip-icon\"\r\n ></span>\r\n }\r\n }\r\n\r\n <span class=\"file-name\" [title]=\"file.objStorage.name ?? ''\">{{\r\n file.objStorage.name\r\n }}</span>\r\n\r\n @if (isAddOrEdit() && file.uploadStatus !== \"loading\") {\r\n <span\r\n nz-icon\r\n nzType=\"delete\"\r\n nzTheme=\"outline\"\r\n title=\"X\u00F3a\"\r\n class=\"delete-icon\"\r\n (click)=\"handleDelete(file); $event.stopPropagation()\"\r\n ></span>\r\n }\r\n\r\n @if (\r\n !isAddOrEdit() &&\r\n file.uploadStatus !== \"error\" &&\r\n file.uploadStatus !== \"loading\"\r\n ) {\r\n <span\r\n nz-icon\r\n nzType=\"eye\"\r\n nzTheme=\"outline\"\r\n class=\"view-icon\"\r\n title=\"Xem file\"\r\n ></span>\r\n }\r\n </li>\r\n }\r\n </ul>\r\n</ng-template>\r\n", styles: [".upload{display:flex}nz-upload .btn-upload{margin-right:.75rem}nz-upload .file-extension-guide{font-size:11px;margin-top:8px;font-style:italic;color:#0f766e}.no-text-info{pointer-events:none;background-color:#fff;color:#575757!important}.custom-upload-list{margin-top:.625rem;list-style-type:none;padding-inline-start:10px}.custom-upload-list .upload-item{margin-bottom:.25rem;display:flex;align-items:center;max-width:100%;gap:.5rem;cursor:pointer;border-radius:4px;transition:background-color .15s ease}.custom-upload-list .upload-item .paper-clip-icon{margin-right:.5rem;color:#595959;flex-shrink:0}.custom-upload-list .upload-item .status-icon{flex-shrink:0}.custom-upload-list .upload-item .loading-icon{color:#1677ff}.custom-upload-list .upload-item .error-icon{color:#ff4d4f}.custom-upload-list .upload-item .file-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.custom-upload-list .upload-item .file-name:hover{text-decoration:underline;color:#0a4c9f;cursor:pointer}.custom-upload-list .upload-item .delete-icon{color:red;cursor:pointer;flex-shrink:0}.custom-upload-list .upload-item .view-icon{color:#1677ff;flex-shrink:0;opacity:.6;transition:opacity .15s ease}.custom-upload-list .upload-item:hover .view-icon{opacity:1}.custom-upload-list .upload-item.is-loading{cursor:default;opacity:.75}.custom-upload-list .upload-item.is-loading .file-name:hover{text-decoration:none;color:inherit;cursor:default}.custom-upload-list .upload-item.is-error{cursor:default}.custom-upload-list .upload-item.is-error .file-name{color:#ff4d4f}.custom-upload-list .upload-item.is-error .file-name:hover{text-decoration:none;color:#ff4d4f;cursor:default}\n"] }]
|
|
3892
4138
|
}], ctorParameters: () => [] });
|
|
3893
4139
|
|
|
3894
|
-
const ZORRO_MODULES$
|
|
4140
|
+
const ZORRO_MODULES$1 = [
|
|
4141
|
+
NzUploadModule,
|
|
4142
|
+
NzIconModule,
|
|
4143
|
+
NzButtonModule,
|
|
4144
|
+
NzImageModule,
|
|
4145
|
+
];
|
|
3895
4146
|
class MultiImageUploadComponent extends BaseValueAccessor {
|
|
3896
4147
|
constructor() {
|
|
3897
4148
|
super();
|
|
3898
4149
|
// Cast lại đúng instance là MultiImageUploadField.
|
|
3899
|
-
this.
|
|
4150
|
+
this.field = computed(() => {
|
|
3900
4151
|
const base = this.fieldInput();
|
|
3901
4152
|
if (!(base instanceof MultiImageUploadField) ||
|
|
3902
|
-
(base.type !== FieldTypeEnum.MultiImageUpload &&
|
|
3903
|
-
|
|
4153
|
+
(base.type !== FieldTypeEnum.MultiImageUpload &&
|
|
4154
|
+
base.controlType !== ControlTypeEnum.Upload)) {
|
|
4155
|
+
throw new Error("Expected MultiImageUploadField");
|
|
3904
4156
|
}
|
|
3905
4157
|
return base;
|
|
3906
4158
|
});
|
|
@@ -3908,9 +4160,8 @@ class MultiImageUploadComponent extends BaseValueAccessor {
|
|
|
3908
4160
|
this.objStorageList = signal([]);
|
|
3909
4161
|
// Mảng đại diện các images.
|
|
3910
4162
|
this.allFiles = signal([]);
|
|
4163
|
+
this.uploading = signal(false);
|
|
3911
4164
|
this.fileService = inject(FileService);
|
|
3912
|
-
this.toast = inject(ToastrService);
|
|
3913
|
-
this.translate = inject(TranslateService);
|
|
3914
4165
|
this.nzNotification = inject(NzNotificationService);
|
|
3915
4166
|
this.formConfigService = inject(FormConfigService);
|
|
3916
4167
|
// Xử lý trước khi upload.
|
|
@@ -3919,13 +4170,10 @@ class MultiImageUploadComponent extends BaseValueAccessor {
|
|
|
3919
4170
|
// Xử lý gán vào CVA để tiến hành validation theo các props đã truyền vào.
|
|
3920
4171
|
const originFile = file;
|
|
3921
4172
|
this.propagateValue(originFile);
|
|
3922
|
-
const { maxFileCount, maxSizeInMB, acceptedMimeTypes } = this.
|
|
4173
|
+
const { maxFileCount, maxSizeInMB, acceptedMimeTypes } = this.field();
|
|
3923
4174
|
// Kiểm tra số lượng tối đa hình ảnh có thể tải lên.
|
|
3924
4175
|
if (this.allFiles().length + 1 > maxFileCount) {
|
|
3925
|
-
|
|
3926
|
-
// this.translate.instant(`Chỉ được phép tải lên tối đa ${maxFileCount} hình ảnh`),
|
|
3927
|
-
// );
|
|
3928
|
-
this.nzNotification.warning('Cảnh báo', `Chỉ được phép tải lên tối đa ${maxFileCount} hình ảnh`, { nzDuration: 4500 });
|
|
4176
|
+
this.nzNotification.warning("Cảnh báo", `Chỉ được phép tải lên tối đa ${maxFileCount} hình ảnh`, { nzDuration: 4500 });
|
|
3929
4177
|
return false;
|
|
3930
4178
|
}
|
|
3931
4179
|
const fileSizeInMB = formatFileSize(file.size, FileSizeTypeEnum.MB);
|
|
@@ -3946,13 +4194,6 @@ class MultiImageUploadComponent extends BaseValueAccessor {
|
|
|
3946
4194
|
// Validation đã thỏa, tiến hành upload file.
|
|
3947
4195
|
return this.uploadFile(originFile);
|
|
3948
4196
|
};
|
|
3949
|
-
// Trigger reset từ bên ngoài form.
|
|
3950
|
-
effect(() => {
|
|
3951
|
-
const reset = this.dFormService.resetTrigger();
|
|
3952
|
-
if (reset?.formId === this.formId) {
|
|
3953
|
-
this.reset();
|
|
3954
|
-
}
|
|
3955
|
-
});
|
|
3956
4197
|
}
|
|
3957
4198
|
// Chạy khi value form được gán bởi các hàm reset, patchValue, setValue.
|
|
3958
4199
|
writeValueToView(value) {
|
|
@@ -3973,17 +4214,18 @@ class MultiImageUploadComponent extends BaseValueAccessor {
|
|
|
3973
4214
|
const objStorageList = JSON.parse(value);
|
|
3974
4215
|
this.objStorageList.set(objStorageList);
|
|
3975
4216
|
// Khởi tạo danh sách MyUploadFile từ data json.
|
|
3976
|
-
const myUploadFiles = objStorageList.map(objStorage => ({
|
|
4217
|
+
const myUploadFiles = objStorageList.map((objStorage) => ({
|
|
3977
4218
|
objStorage,
|
|
3978
4219
|
isTemp: false,
|
|
3979
|
-
previewUrl: this.formConfigService.getViewFileUrl(objStorage.name ??
|
|
4220
|
+
previewUrl: this.formConfigService.getViewFileUrl(objStorage.name ?? "", false),
|
|
3980
4221
|
}));
|
|
3981
4222
|
this.allFiles.set(myUploadFiles);
|
|
3982
4223
|
}
|
|
3983
4224
|
}
|
|
3984
4225
|
uploadFile(file) {
|
|
3985
|
-
|
|
3986
|
-
const
|
|
4226
|
+
this.uploading.set(true);
|
|
4227
|
+
const { apiFileConfig, uploadTemp } = this.field();
|
|
4228
|
+
const newFileName = this.formConfigService.generateRandomFileName(file.name, "file");
|
|
3987
4229
|
const renamedFile = new File([file], newFileName, { type: file.type });
|
|
3988
4230
|
const mimeCfg = apiFileConfig.perMimeTypeConfig?.[file.type]; // Lấy mimeTypes file upload.
|
|
3989
4231
|
const uploadUrl = mimeCfg?.uploadUrl ?? apiFileConfig.uploadUrl; // Nếu có config upload riêng cho mimeTypes đang kiểm tra.
|
|
@@ -3992,26 +4234,26 @@ class MultiImageUploadComponent extends BaseValueAccessor {
|
|
|
3992
4234
|
: (() => {
|
|
3993
4235
|
// Mặc định
|
|
3994
4236
|
const fd = new FormData();
|
|
3995
|
-
fd.append(
|
|
4237
|
+
fd.append("File", renamedFile);
|
|
3996
4238
|
// fd.append('isTemp', 'true');
|
|
3997
4239
|
return fd;
|
|
3998
4240
|
})();
|
|
3999
4241
|
if (uploadTemp)
|
|
4000
|
-
formData.append(
|
|
4242
|
+
formData.append("isTemp", "true");
|
|
4001
4243
|
return this.fileService
|
|
4002
4244
|
.uploadFile(renamedFile, formData, { uploadUrl })
|
|
4003
|
-
.pipe(this.takeUntilDestroy())
|
|
4245
|
+
.pipe(this.takeUntilDestroy(), finalize(() => this.uploading.set(false)))
|
|
4004
4246
|
.subscribe({
|
|
4005
|
-
next: res => {
|
|
4247
|
+
next: (res) => {
|
|
4006
4248
|
const { code, data, message } = res;
|
|
4007
4249
|
if (code === 0) {
|
|
4008
|
-
this.objStorageList.update(curr => [...curr, data]);
|
|
4009
|
-
this.allFiles.update(curr => [
|
|
4250
|
+
this.objStorageList.update((curr) => [...curr, data]);
|
|
4251
|
+
this.allFiles.update((curr) => [
|
|
4010
4252
|
...curr,
|
|
4011
4253
|
{
|
|
4012
4254
|
objStorage: data,
|
|
4013
4255
|
isTemp: true,
|
|
4014
|
-
previewUrl: this.formConfigService.getViewFileUrl(data.name ??
|
|
4256
|
+
previewUrl: this.formConfigService.getViewFileUrl(data.name ?? "", true),
|
|
4015
4257
|
},
|
|
4016
4258
|
]);
|
|
4017
4259
|
this.patchFormData(this.fieldKey(), JSON.stringify(this.objStorageList()));
|
|
@@ -4021,30 +4263,32 @@ class MultiImageUploadComponent extends BaseValueAccessor {
|
|
|
4021
4263
|
}
|
|
4022
4264
|
},
|
|
4023
4265
|
error: (err) => {
|
|
4024
|
-
console.error(
|
|
4266
|
+
console.error("Lỗi trong quá trình tải hình ảnh đến máy chủ!!");
|
|
4025
4267
|
},
|
|
4026
4268
|
});
|
|
4027
4269
|
}
|
|
4028
4270
|
handleDelete(file) {
|
|
4029
4271
|
const { objStorage } = file;
|
|
4030
4272
|
// Loại bỏ và cập nhật danh sách ObjectStorage.
|
|
4031
|
-
const newObjStorageList = this.objStorageList().filter(item => item.id !== objStorage?.id);
|
|
4273
|
+
const newObjStorageList = this.objStorageList().filter((item) => item.id !== objStorage?.id);
|
|
4032
4274
|
this.objStorageList.set(newObjStorageList);
|
|
4033
4275
|
// Loại bỏ và cập nhật danh sách MyUploadFile.
|
|
4034
|
-
const newAllFiles = this.allFiles().filter(item => item.objStorage?.id !== objStorage?.id);
|
|
4276
|
+
const newAllFiles = this.allFiles().filter((item) => item.objStorage?.id !== objStorage?.id);
|
|
4035
4277
|
this.allFiles.set(newAllFiles);
|
|
4036
4278
|
// Cập nhật đầu ra cho form.
|
|
4037
4279
|
this.patchFormData(this.fieldKey(), JSON.stringify(this.objStorageList()));
|
|
4038
4280
|
}
|
|
4039
4281
|
deleteObjStorage(id) {
|
|
4040
4282
|
return this.fileService
|
|
4041
|
-
.deleteObjStorage(id, {
|
|
4283
|
+
.deleteObjStorage(id, {
|
|
4284
|
+
deleteUrl: this.field().apiFileConfig.deleteUrl,
|
|
4285
|
+
})
|
|
4042
4286
|
.pipe(this.takeUntilDestroy())
|
|
4043
4287
|
.subscribe({
|
|
4044
|
-
next: res => {
|
|
4288
|
+
next: (res) => {
|
|
4045
4289
|
const { code, message } = res;
|
|
4046
4290
|
if (code === 0) {
|
|
4047
|
-
const newObjStorageList = this.objStorageList().filter(item => item.id !== id);
|
|
4291
|
+
const newObjStorageList = this.objStorageList().filter((item) => item.id !== id);
|
|
4048
4292
|
this.objStorageList.set(newObjStorageList);
|
|
4049
4293
|
this.patchFormData(this.fieldKey(), JSON.stringify(this.objStorageList()));
|
|
4050
4294
|
}
|
|
@@ -4053,9 +4297,9 @@ class MultiImageUploadComponent extends BaseValueAccessor {
|
|
|
4053
4297
|
}
|
|
4054
4298
|
},
|
|
4055
4299
|
error: (err) => {
|
|
4056
|
-
console.error(
|
|
4300
|
+
console.error("Lỗi trong quá trình xóa tập tin khỏi máy chủ!!");
|
|
4057
4301
|
// Fake vì hiện api xóa đang có vấn đề.
|
|
4058
|
-
const newObjStorageList = this.objStorageList().filter(item => item.id !== id);
|
|
4302
|
+
const newObjStorageList = this.objStorageList().filter((item) => item.id !== id);
|
|
4059
4303
|
this.objStorageList.set(newObjStorageList);
|
|
4060
4304
|
this.patchFormData(this.fieldKey(), JSON.stringify(this.objStorageList()));
|
|
4061
4305
|
// Fake vì hiện api xóa đang có vấn đề.
|
|
@@ -4074,51 +4318,85 @@ class MultiImageUploadComponent extends BaseValueAccessor {
|
|
|
4074
4318
|
useExisting: forwardRef(() => MultiImageUploadComponent),
|
|
4075
4319
|
multi: true,
|
|
4076
4320
|
},
|
|
4077
|
-
], usesInheritance: true, ngImport: i0, template: "@if (isAddOrEdit()) {\r\n <div class=\"upload\">\r\n <nz-upload\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"false\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n >\r\n <button nz-button class=\"btn-upload\">\r\n T\u1EA3i l\u00EAn\r\n <nz-icon nzType=\"upload\" nzTheme=\"outline\" />\r\n </button>\r\n\r\n <span
|
|
4321
|
+
], usesInheritance: true, ngImport: i0, template: "@if (isAddOrEdit()) {\r\n <div class=\"upload\">\r\n <nz-upload\r\n [nzDisabled]=\"\r\n allFiles().length >= field().maxFileCount ||\r\n disabledSignal() ||\r\n uploading()\r\n \"\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"false\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n >\r\n <button nz-button class=\"btn-upload\" [nzLoading]=\"uploading()\">\r\n T\u1EA3i l\u00EAn\r\n @if (!uploading()) {\r\n <nz-icon nzType=\"upload\" nzTheme=\"outline\" />\r\n }\r\n </button>\r\n\r\n <span class=\"ms-2 text-muted fs-12\">\r\n (\u0110\u00E3 t\u1EA3i l\u00EAn {{ allFiles().length }}/{{ field().maxFileCount }}\r\n h\u00ECnh \u1EA3nh)\r\n </span>\r\n </nz-upload>\r\n </div>\r\n}\r\n\r\n<!-- Custom hi\u1EC3n th\u1ECB danh s\u00E1ch h\u00ECnh \u1EA3nh -->\r\n@if (allFiles().length > 0) {\r\n <ng-container *ngTemplateOutlet=\"imageGroupTpl\"></ng-container>\r\n}\r\n\r\n<!-- Template custom hi\u1EC3n th\u1ECB danh s\u00E1ch h\u00ECnh \u1EA3nh -->\r\n<ng-template #imageGroupTpl>\r\n <nz-image-group>\r\n <div class=\"image-list\">\r\n @for (file of allFiles(); track file.objStorage?.id; let i = $index) {\r\n <div\r\n class=\"image-card-container\"\r\n [ngStyle]=\"{\r\n width: field().imageCardWidth,\r\n height: field().imageCardHeight,\r\n }\"\r\n >\r\n <div class=\"image-item\">\r\n <div class=\"image-item-info\">\r\n <img\r\n [id]=\"file.objStorage.id\"\r\n nz-image\r\n nzSrc=\"{{ file.previewUrl }}\"\r\n alt=\"{{ file.objStorage.originalName }}\"\r\n />\r\n </div>\r\n\r\n <div class=\"image-item-actions\">\r\n <button\r\n nz-button\r\n nzType=\"text\"\r\n nzSize=\"small\"\r\n (click)=\"handlePreview(file)\"\r\n >\r\n <nz-icon nzType=\"eye\" nzTheme=\"outline\" />\r\n </button>\r\n\r\n @if (isAddOrEdit()) {\r\n <button\r\n nz-button\r\n nzType=\"text\"\r\n nzSize=\"small\"\r\n (click)=\"handleDelete(file)\"\r\n >\r\n <nz-icon nzType=\"delete\" nzTheme=\"outline\" />\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </nz-image-group>\r\n</ng-template>\r\n", styles: [".upload{margin-bottom:.625rem}.upload nz-upload .btn-upload{margin-right:.75rem}.image-list{display:flex;gap:8px;flex-wrap:nowrap;overflow-x:auto}.image-list .image-card-container{display:inline-block;margin:0px .5rem .5rem 0;flex:0 0 auto}.image-list .image-card-container .image-item{padding:.5rem;border:1px solid #cbd5e1;height:100%;cursor:pointer;position:relative}.image-list .image-card-container .image-item .image-item-info{position:relative;height:100%;overflow:hidden}.image-list .image-card-container .image-item .image-item-info img{display:block;width:100%;height:100%;object-fit:contain}.image-list .image-card-container .image-item .image-item-info:before{position:absolute;z-index:1;width:100%;height:100%;background-color:#00000080;opacity:0;transition:all .3s;content:\" \"}.image-list .image-card-container .image-item .image-item-actions{position:absolute;top:50%;left:50%;z-index:10;white-space:nowrap;transform:translate(-50%,-50%);transition:all .5s;opacity:0}.image-list .image-card-container .image-item .image-item-actions>button nz-icon{font-size:1rem!important;color:#fdfdfdd9}.image-list .image-card-container .image-item:hover .image-item-info:before,.image-list .image-card-container .image-item:hover .image-item-actions{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: i1$2.CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: NzUploadModule }, { kind: "component", type: i2$2.NzUploadComponent, selector: "nz-upload", inputs: ["nzType", "nzLimit", "nzSize", "nzFileType", "nzAccept", "nzAction", "nzDirectory", "nzOpenFileDialogOnClick", "nzBeforeUpload", "nzCustomRequest", "nzData", "nzFilter", "nzFileList", "nzDisabled", "nzHeaders", "nzListType", "nzMultiple", "nzName", "nzShowUploadList", "nzShowButton", "nzWithCredentials", "nzRemove", "nzPreview", "nzPreviewFile", "nzPreviewIsImage", "nzTransformFile", "nzDownload", "nzIconRender", "nzFileListRender"], outputs: ["nzChange", "nzFileListChange"], exportAs: ["nzUpload"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i4.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i5.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i6.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzImageModule }, { kind: "directive", type: i7.NzImageDirective, selector: "img[nz-image]", inputs: ["nzSrc", "nzSrcset", "nzDisablePreview", "nzFallback", "nzPlaceholder", "nzScaleStep"], exportAs: ["nzImage"] }, { kind: "component", type: i7.NzImageGroupComponent, selector: "nz-image-group", inputs: ["nzScaleStep"], exportAs: ["nzImageGroup"] }] }); }
|
|
4078
4322
|
}
|
|
4079
4323
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MultiImageUploadComponent, decorators: [{
|
|
4080
4324
|
type: Component,
|
|
4081
|
-
args: [{ selector:
|
|
4325
|
+
args: [{ selector: "app-multi-image-upload", standalone: true, imports: [...CORE_MODULES, ...ZORRO_MODULES$1], providers: [
|
|
4082
4326
|
{
|
|
4083
4327
|
provide: NG_VALUE_ACCESSOR,
|
|
4084
4328
|
useExisting: forwardRef(() => MultiImageUploadComponent),
|
|
4085
4329
|
multi: true,
|
|
4086
4330
|
},
|
|
4087
|
-
], template: "@if (isAddOrEdit()) {\r\n <div class=\"upload\">\r\n <nz-upload\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"false\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n >\r\n <button nz-button class=\"btn-upload\">\r\n T\u1EA3i l\u00EAn\r\n <nz-icon nzType=\"upload\" nzTheme=\"outline\" />\r\n </button>\r\n\r\n <span
|
|
4331
|
+
], template: "@if (isAddOrEdit()) {\r\n <div class=\"upload\">\r\n <nz-upload\r\n [nzDisabled]=\"\r\n allFiles().length >= field().maxFileCount ||\r\n disabledSignal() ||\r\n uploading()\r\n \"\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"false\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n >\r\n <button nz-button class=\"btn-upload\" [nzLoading]=\"uploading()\">\r\n T\u1EA3i l\u00EAn\r\n @if (!uploading()) {\r\n <nz-icon nzType=\"upload\" nzTheme=\"outline\" />\r\n }\r\n </button>\r\n\r\n <span class=\"ms-2 text-muted fs-12\">\r\n (\u0110\u00E3 t\u1EA3i l\u00EAn {{ allFiles().length }}/{{ field().maxFileCount }}\r\n h\u00ECnh \u1EA3nh)\r\n </span>\r\n </nz-upload>\r\n </div>\r\n}\r\n\r\n<!-- Custom hi\u1EC3n th\u1ECB danh s\u00E1ch h\u00ECnh \u1EA3nh -->\r\n@if (allFiles().length > 0) {\r\n <ng-container *ngTemplateOutlet=\"imageGroupTpl\"></ng-container>\r\n}\r\n\r\n<!-- Template custom hi\u1EC3n th\u1ECB danh s\u00E1ch h\u00ECnh \u1EA3nh -->\r\n<ng-template #imageGroupTpl>\r\n <nz-image-group>\r\n <div class=\"image-list\">\r\n @for (file of allFiles(); track file.objStorage?.id; let i = $index) {\r\n <div\r\n class=\"image-card-container\"\r\n [ngStyle]=\"{\r\n width: field().imageCardWidth,\r\n height: field().imageCardHeight,\r\n }\"\r\n >\r\n <div class=\"image-item\">\r\n <div class=\"image-item-info\">\r\n <img\r\n [id]=\"file.objStorage.id\"\r\n nz-image\r\n nzSrc=\"{{ file.previewUrl }}\"\r\n alt=\"{{ file.objStorage.originalName }}\"\r\n />\r\n </div>\r\n\r\n <div class=\"image-item-actions\">\r\n <button\r\n nz-button\r\n nzType=\"text\"\r\n nzSize=\"small\"\r\n (click)=\"handlePreview(file)\"\r\n >\r\n <nz-icon nzType=\"eye\" nzTheme=\"outline\" />\r\n </button>\r\n\r\n @if (isAddOrEdit()) {\r\n <button\r\n nz-button\r\n nzType=\"text\"\r\n nzSize=\"small\"\r\n (click)=\"handleDelete(file)\"\r\n >\r\n <nz-icon nzType=\"delete\" nzTheme=\"outline\" />\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </nz-image-group>\r\n</ng-template>\r\n", styles: [".upload{margin-bottom:.625rem}.upload nz-upload .btn-upload{margin-right:.75rem}.image-list{display:flex;gap:8px;flex-wrap:nowrap;overflow-x:auto}.image-list .image-card-container{display:inline-block;margin:0px .5rem .5rem 0;flex:0 0 auto}.image-list .image-card-container .image-item{padding:.5rem;border:1px solid #cbd5e1;height:100%;cursor:pointer;position:relative}.image-list .image-card-container .image-item .image-item-info{position:relative;height:100%;overflow:hidden}.image-list .image-card-container .image-item .image-item-info img{display:block;width:100%;height:100%;object-fit:contain}.image-list .image-card-container .image-item .image-item-info:before{position:absolute;z-index:1;width:100%;height:100%;background-color:#00000080;opacity:0;transition:all .3s;content:\" \"}.image-list .image-card-container .image-item .image-item-actions{position:absolute;top:50%;left:50%;z-index:10;white-space:nowrap;transform:translate(-50%,-50%);transition:all .5s;opacity:0}.image-list .image-card-container .image-item .image-item-actions>button nz-icon{font-size:1rem!important;color:#fdfdfdd9}.image-list .image-card-container .image-item:hover .image-item-info:before,.image-list .image-card-container .image-item:hover .image-item-actions{opacity:1}\n"] }]
|
|
4088
4332
|
}], ctorParameters: () => [] });
|
|
4089
4333
|
|
|
4090
|
-
const
|
|
4091
|
-
const
|
|
4334
|
+
const modules$1 = [CommonModule];
|
|
4335
|
+
const zorroModules$1 = [
|
|
4336
|
+
NzUploadModule,
|
|
4337
|
+
NzIconModule,
|
|
4338
|
+
NzInputModule,
|
|
4339
|
+
NzButtonModule,
|
|
4340
|
+
NzSpinModule,
|
|
4341
|
+
];
|
|
4342
|
+
const components$1 = [SuffixComponent];
|
|
4092
4343
|
class SingleFileUploadComponent extends BaseValueAccessor {
|
|
4093
4344
|
constructor() {
|
|
4094
4345
|
super();
|
|
4095
|
-
this.
|
|
4346
|
+
this.field = computed(() => {
|
|
4096
4347
|
const base = this.fieldInput();
|
|
4097
4348
|
if (!(base instanceof SingleFileUploadField) ||
|
|
4098
|
-
(base.type !== FieldTypeEnum.SingleFileUpload &&
|
|
4099
|
-
|
|
4349
|
+
(base.type !== FieldTypeEnum.SingleFileUpload &&
|
|
4350
|
+
base.controlType !== ControlTypeEnum.Upload)) {
|
|
4351
|
+
throw new Error("Expected SingleFileUploadField");
|
|
4100
4352
|
}
|
|
4101
4353
|
return base;
|
|
4102
4354
|
});
|
|
4355
|
+
// Inject services
|
|
4356
|
+
this.fileService = inject(FileService);
|
|
4357
|
+
this.nzNotification = inject(NzNotificationService);
|
|
4358
|
+
this.formConfigService = inject(FormConfigService);
|
|
4103
4359
|
// Mảng lưu trữ objectStorage liên quan đến tập tin.
|
|
4104
4360
|
this.objStorageList = signal([]);
|
|
4105
4361
|
// Mảng đại diện các files.
|
|
4106
4362
|
this.allFiles = signal([]);
|
|
4107
4363
|
// Text hướng dẫn các loại extension được upload.
|
|
4108
|
-
this.fileExtensionGuide =
|
|
4109
|
-
|
|
4364
|
+
this.fileExtensionGuide = computed(() => {
|
|
4365
|
+
if (!this.isAddOrEdit())
|
|
4366
|
+
return "";
|
|
4367
|
+
const { acceptedMimeTypes } = this.field();
|
|
4368
|
+
return `Hỗ trợ định dạng ${getExtensions(acceptedMimeTypes).join(", ")}`;
|
|
4369
|
+
});
|
|
4370
|
+
this.viewDisplayValue = computed(() => {
|
|
4371
|
+
// 1. Nếu không phải View thì không cần quan tâm text này
|
|
4372
|
+
if (!this.isView())
|
|
4373
|
+
return "";
|
|
4374
|
+
if (this.allFiles().length === 0)
|
|
4375
|
+
return NO_INFO_TEXT;
|
|
4376
|
+
const { objStorage } = this.allFiles()[0];
|
|
4377
|
+
const { nameAlias, name } = objStorage;
|
|
4378
|
+
if (!nameAlias && !name)
|
|
4379
|
+
return NO_INFO_TEXT;
|
|
4380
|
+
return nameAlias ?? name;
|
|
4381
|
+
});
|
|
4382
|
+
this.addEditDisplayValue = computed(() => {
|
|
4383
|
+
if (!this.isAddOrEdit())
|
|
4384
|
+
return "";
|
|
4385
|
+
if (this.allFiles().length === 0)
|
|
4386
|
+
return UPLOAD_FILE_TEXT;
|
|
4387
|
+
const { objStorage } = this.allFiles()[0];
|
|
4388
|
+
const { nameAlias, name } = objStorage;
|
|
4389
|
+
if (!nameAlias && !name)
|
|
4390
|
+
return NO_FILE_NAME;
|
|
4391
|
+
return nameAlias ?? name;
|
|
4392
|
+
});
|
|
4110
4393
|
this.uploading = signal(false);
|
|
4111
|
-
this.fileService = inject(FileService);
|
|
4112
|
-
this.toast = inject(ToastrService);
|
|
4113
|
-
this.translate = inject(TranslateService);
|
|
4114
|
-
this.nzNotification = inject(NzNotificationService);
|
|
4115
|
-
this.formConfigService = inject(FormConfigService);
|
|
4116
4394
|
this.beforeUpload = (file, fileList) => {
|
|
4117
4395
|
// const originFile = file?.originFileObj as unknown as File; // có thể ở version mới nhất đã fix lỗi NzUploadFile nhưng trả về File của tham số file.
|
|
4118
4396
|
// Xử lý gán vào CVA để tiến hành validation theo các props đã truyền vào.
|
|
4119
4397
|
const originFile = file;
|
|
4120
4398
|
this.propagateValue(originFile);
|
|
4121
|
-
const { maxSizeInMB, acceptedMimeTypes } = this.
|
|
4399
|
+
const { maxSizeInMB, acceptedMimeTypes } = this.field();
|
|
4122
4400
|
const fileSizeInMB = formatFileSize(file.size, FileSizeTypeEnum.MB);
|
|
4123
4401
|
const fileType = file.type;
|
|
4124
4402
|
if (fileSizeInMB > maxSizeInMB || !acceptedMimeTypes.includes(fileType)) {
|
|
@@ -4136,27 +4414,6 @@ class SingleFileUploadComponent extends BaseValueAccessor {
|
|
|
4136
4414
|
// Validation đã thỏa, tiến hành upload file.
|
|
4137
4415
|
return this.uploadFile(originFile);
|
|
4138
4416
|
};
|
|
4139
|
-
// 1. Effect chung Add + Edit
|
|
4140
|
-
effect(() => {
|
|
4141
|
-
if (this.isAddOrEdit()) {
|
|
4142
|
-
const field = untracked(() => this.fieldSignal());
|
|
4143
|
-
const { acceptedMimeTypes } = field;
|
|
4144
|
-
this.fileExtensionGuide.set(`Hỗ trợ định dạng ${getExtensions(acceptedMimeTypes).join(', ')}`);
|
|
4145
|
-
}
|
|
4146
|
-
});
|
|
4147
|
-
// Trigger reset từ bên ngoài form.
|
|
4148
|
-
effect(() => {
|
|
4149
|
-
const reset = this.dFormService.resetTrigger();
|
|
4150
|
-
if (reset?.formId === this.formId) {
|
|
4151
|
-
this.reset();
|
|
4152
|
-
}
|
|
4153
|
-
});
|
|
4154
|
-
effect(() => {
|
|
4155
|
-
const allFiles = this.allFiles();
|
|
4156
|
-
this.inputDisplayValue = allFiles[0]
|
|
4157
|
-
? (allFiles[0].objStorage.nameAlias ?? allFiles[0].objStorage.name) || 'Không có thông tin'
|
|
4158
|
-
: 'Không có thông tin';
|
|
4159
|
-
});
|
|
4160
4417
|
}
|
|
4161
4418
|
// Chạy khi value form được gán bởi các hàm reset, patchValue, setValue.
|
|
4162
4419
|
writeValueToView(value) {
|
|
@@ -4176,7 +4433,7 @@ class SingleFileUploadComponent extends BaseValueAccessor {
|
|
|
4176
4433
|
const objStorageList = JSON.parse(value);
|
|
4177
4434
|
this.objStorageList.set(objStorageList);
|
|
4178
4435
|
// Khởi tạo danh sách MyUploadFile từ data json.
|
|
4179
|
-
const myUploadFiles = objStorageList.map(objStorage => ({
|
|
4436
|
+
const myUploadFiles = objStorageList.map((objStorage) => ({
|
|
4180
4437
|
objStorage,
|
|
4181
4438
|
isTemp: false,
|
|
4182
4439
|
previewUrl: `${this.formConfigService.getStorageUrl()}${objStorage.bucket}/${objStorage.path}`,
|
|
@@ -4186,14 +4443,18 @@ class SingleFileUploadComponent extends BaseValueAccessor {
|
|
|
4186
4443
|
else {
|
|
4187
4444
|
if (value) {
|
|
4188
4445
|
this.allFiles.set([
|
|
4189
|
-
{
|
|
4446
|
+
{
|
|
4447
|
+
isTemp: false,
|
|
4448
|
+
objStorage: { id: "", name: value },
|
|
4449
|
+
previewUrl: "",
|
|
4450
|
+
},
|
|
4190
4451
|
]);
|
|
4191
4452
|
}
|
|
4192
4453
|
}
|
|
4193
4454
|
}
|
|
4194
4455
|
uploadFile(file) {
|
|
4195
4456
|
this.uploading.set(true);
|
|
4196
|
-
const { apiFileConfig, uploadTemp } = this.
|
|
4457
|
+
const { apiFileConfig, uploadTemp } = this.field();
|
|
4197
4458
|
const newFileName = FormUtils.randomFileName(file.name);
|
|
4198
4459
|
const mimeCfg = apiFileConfig.perMimeTypeConfig?.[file.type]; // Lấy mimeTypes file upload.
|
|
4199
4460
|
const uploadUrl = mimeCfg?.uploadUrl ?? apiFileConfig.uploadUrl; // Nếu có config upload riêng cho mimeTypes đang kiểm tra.
|
|
@@ -4204,23 +4465,23 @@ class SingleFileUploadComponent extends BaseValueAccessor {
|
|
|
4204
4465
|
: (() => {
|
|
4205
4466
|
// Mặc định
|
|
4206
4467
|
const fd = new FormData();
|
|
4207
|
-
fd.append(
|
|
4468
|
+
fd.append("File", file, newFileName);
|
|
4208
4469
|
if (apiFileConfig.uploadByPath && apiFileConfig.uploadPath) {
|
|
4209
|
-
fd.append(
|
|
4470
|
+
fd.append("path", apiFileConfig.uploadPath);
|
|
4210
4471
|
}
|
|
4211
4472
|
if (apiFileConfig.isOriginName) {
|
|
4212
|
-
fd.append(
|
|
4473
|
+
fd.append("nameAlias", file.name);
|
|
4213
4474
|
}
|
|
4214
4475
|
// fd.append('isTemp', 'true');
|
|
4215
4476
|
return fd;
|
|
4216
4477
|
})();
|
|
4217
4478
|
if (uploadTemp)
|
|
4218
|
-
formData.append(
|
|
4479
|
+
formData.append("isTemp", "true");
|
|
4219
4480
|
return this.fileService
|
|
4220
4481
|
.uploadFile(file, formData, { uploadUrl })
|
|
4221
4482
|
.pipe(this.takeUntilDestroy(), finalize(() => this.uploading.set(false)))
|
|
4222
4483
|
.subscribe({
|
|
4223
|
-
next: res => {
|
|
4484
|
+
next: (res) => {
|
|
4224
4485
|
const { code, data, message } = res;
|
|
4225
4486
|
if (code === 0) {
|
|
4226
4487
|
this.objStorageList.set([data]);
|
|
@@ -4229,7 +4490,7 @@ class SingleFileUploadComponent extends BaseValueAccessor {
|
|
|
4229
4490
|
objStorage: data,
|
|
4230
4491
|
isTemp: true,
|
|
4231
4492
|
previewUrl: uploadTemp
|
|
4232
|
-
? this.formConfigService.getViewFileUrl(data.name ??
|
|
4493
|
+
? this.formConfigService.getViewFileUrl(data.name ?? "", true)
|
|
4233
4494
|
: `${this.formConfigService.getStorageUrl()}${data.bucket}/${data.path}`,
|
|
4234
4495
|
},
|
|
4235
4496
|
]);
|
|
@@ -4240,19 +4501,19 @@ class SingleFileUploadComponent extends BaseValueAccessor {
|
|
|
4240
4501
|
}
|
|
4241
4502
|
},
|
|
4242
4503
|
error: () => {
|
|
4243
|
-
console.error(
|
|
4504
|
+
console.error(UPLOAD_FILE_ERROR);
|
|
4244
4505
|
},
|
|
4245
4506
|
});
|
|
4246
4507
|
}
|
|
4247
4508
|
handleDelete(file) {
|
|
4248
4509
|
const { objStorage } = file;
|
|
4249
|
-
const { uploadTemp } = this.
|
|
4510
|
+
const { uploadTemp } = this.field();
|
|
4250
4511
|
this.objStorageList.set([]);
|
|
4251
4512
|
// Loại bỏ và cập nhật danh sách MyUploadFile.
|
|
4252
|
-
const newAllFiles = this.allFiles().filter(item => item.objStorage?.id !== objStorage?.id);
|
|
4513
|
+
const newAllFiles = this.allFiles().filter((item) => item.objStorage?.id !== objStorage?.id);
|
|
4253
4514
|
this.allFiles.set(newAllFiles);
|
|
4254
4515
|
if (!uploadTemp) {
|
|
4255
|
-
this.deleteObjStorage(objStorage.id ||
|
|
4516
|
+
this.deleteObjStorage(objStorage.id || "");
|
|
4256
4517
|
return;
|
|
4257
4518
|
}
|
|
4258
4519
|
this.patchFormData(this.fieldKey(), JSON.stringify(this.objStorageList()));
|
|
@@ -4260,10 +4521,12 @@ class SingleFileUploadComponent extends BaseValueAccessor {
|
|
|
4260
4521
|
}
|
|
4261
4522
|
deleteObjStorage(id) {
|
|
4262
4523
|
return this.fileService
|
|
4263
|
-
.deleteObjStorage(id, {
|
|
4524
|
+
.deleteObjStorage(id, {
|
|
4525
|
+
deleteUrl: this.field().apiFileConfig.deleteUrl,
|
|
4526
|
+
})
|
|
4264
4527
|
.pipe(this.takeUntilDestroy())
|
|
4265
4528
|
.subscribe({
|
|
4266
|
-
next: res => {
|
|
4529
|
+
next: (res) => {
|
|
4267
4530
|
const { code, message } = res;
|
|
4268
4531
|
if (code === 0) {
|
|
4269
4532
|
this.objStorageList.set([]);
|
|
@@ -4274,7 +4537,7 @@ class SingleFileUploadComponent extends BaseValueAccessor {
|
|
|
4274
4537
|
}
|
|
4275
4538
|
},
|
|
4276
4539
|
error: () => {
|
|
4277
|
-
console.error(
|
|
4540
|
+
console.error(DELETE_FILE_ERROR);
|
|
4278
4541
|
// Tạm do api xóa có vấn đề
|
|
4279
4542
|
this.objStorageList.set([]);
|
|
4280
4543
|
this.patchFormData(this.fieldKey(), JSON.stringify(this.objStorageList()));
|
|
@@ -4288,23 +4551,24 @@ class SingleFileUploadComponent extends BaseValueAccessor {
|
|
|
4288
4551
|
useExisting: forwardRef(() => SingleFileUploadComponent),
|
|
4289
4552
|
multi: true,
|
|
4290
4553
|
},
|
|
4291
|
-
], usesInheritance: true, ngImport: i0, template: "<div class=\"d-flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
4554
|
+
], usesInheritance: true, ngImport: i0, template: "<div class=\"d-flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n <input nz-input [value]=\"viewDisplayValue()\" class=\"modeView\" />\r\n }\r\n @if (viewMode() === viewModeEnum.text) {\r\n <span class=\"modeView\">{{ viewDisplayValue() }}</span>\r\n }\r\n }\r\n @if (isAddOrEdit()) {\r\n <div class=\"flex w-100\">\r\n <nz-input-group\r\n [nzSuffix]=\"\r\n uploading() || (allFiles().length > 0 && isAddOrEdit())\r\n ? actionIcon\r\n : undefined\r\n \"\r\n class=\"flex-1\"\r\n >\r\n <input\r\n nz-input\r\n [value]=\"\r\n uploading() ? '\u0110ang t\u1EA3i l\u00EAn t\u1EADp tin...' : addEditDisplayValue()\r\n \"\r\n class=\"no-events\"\r\n />\r\n </nz-input-group>\r\n\r\n <nz-upload\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"false\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n >\r\n <button\r\n nz-button\r\n class=\"btn-upload h-100 text-white\"\r\n [disabled]=\"uploading()\"\r\n >\r\n <span class=\"fs-12\">T\u1EA3i l\u00EAn</span>\r\n <nz-icon nzType=\"upload\" nzTheme=\"outline\" />\r\n </button>\r\n </nz-upload>\r\n </div>\r\n }\r\n\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\" [formId]=\"formId\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n\r\n<ng-template #actionIcon>\r\n @if (uploading()) {\r\n <span\r\n nz-icon\r\n nzType=\"loading\"\r\n nzTheme=\"outline\"\r\n class=\"text-primary\"\r\n ></span>\r\n } @else if (allFiles().length > 0 && isAddOrEdit()) {\r\n <span\r\n title=\"X\u00F3a\"\r\n class=\"mdi mdi-delete pointer text-danger\"\r\n (click)=\"handleDelete(allFiles()[0])\"\r\n ></span>\r\n }\r\n</ng-template>\r\n\r\n@if (field().showAcceptedExtensionGuide && fileExtensionGuide()) {\r\n <div class=\"file-extension-guide\">{{ fileExtensionGuide() }}</div>\r\n}\r\n\r\n<!-- Custom hi\u1EC3n th\u1ECB danh s\u00E1ch t\u1EADp tin -->\r\n<!-- @if (allFiles().length > 0) { -->\r\n<!-- <ng-container *ngTemplateOutlet=\"renderFileTpl\"></ng-container> -->\r\n<!-- } -->\r\n\r\n<!-- Template custom hi\u1EC3n th\u1ECB danh s\u00E1ch t\u1EADp tin -->\r\n<!-- <ng-template #renderFileTpl>\r\n <ul class=\"custom-upload-list\">\r\n @for (file of allFiles() | slice: 0 : 1; track file.objStorage?.id) {\r\n <li class=\"upload-item\">\r\n <span nz-icon nzType=\"paper-clip\" nzTheme=\"outline\" class=\"paper-clip-icon\"></span>\r\n\r\n <span class=\"filename\">{{ file.objStorage.name }}</span>\r\n\r\n @if (isAddOrEdit()) {\r\n <span\r\n nz-icon\r\n nzType=\"delete\"\r\n nzTheme=\"outline\"\r\n title=\"X\u00F3a\"\r\n class=\"delete-icon\"\r\n (click)=\"handleDelete(file)\"\r\n ></span>\r\n }\r\n </li>\r\n }\r\n </ul>\r\n</ng-template> -->\r\n", styles: [".file-extension-guide{font-size:11px;margin-top:8px;font-style:italic;color:#0f766e}.custom-upload-list{margin-top:.625rem;list-style-type:none;padding-inline-start:10px}.custom-upload-list .paper-clip-icon{margin-right:.5rem}.custom-upload-list .delete-icon{color:red;cursor:pointer;margin-left:.5rem}.file-name:hover{text-decoration:underline;color:#0a4c9f;cursor:pointer}.btn-upload{background-color:#2666ab}.no-events{pointer-events:none;color:#cdbfbf}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NzUploadModule }, { kind: "component", type: i2$2.NzUploadComponent, selector: "nz-upload", inputs: ["nzType", "nzLimit", "nzSize", "nzFileType", "nzAccept", "nzAction", "nzDirectory", "nzOpenFileDialogOnClick", "nzBeforeUpload", "nzCustomRequest", "nzData", "nzFilter", "nzFileList", "nzDisabled", "nzHeaders", "nzListType", "nzMultiple", "nzName", "nzShowUploadList", "nzShowButton", "nzWithCredentials", "nzRemove", "nzPreview", "nzPreviewFile", "nzPreviewIsImage", "nzTransformFile", "nzDownload", "nzIconRender", "nzFileListRender"], outputs: ["nzChange", "nzFileListChange"], exportAs: ["nzUpload"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i1$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "component", type: i1$1.NzInputGroupComponent, selector: "nz-input-group", inputs: ["nzAddOnBeforeIcon", "nzAddOnAfterIcon", "nzPrefixIcon", "nzSuffixIcon", "nzAddOnBefore", "nzAddOnAfter", "nzPrefix", "nzStatus", "nzSuffix", "nzSize", "nzSearch", "nzCompact"], exportAs: ["nzInputGroup"] }, { kind: "directive", type: i1$1.NzInputGroupWhitSuffixOrPrefixDirective, selector: "nz-input-group[nzSuffix], nz-input-group[nzPrefix]" }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i4.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i5.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i6.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzSpinModule }, { kind: "component", type: SuffixComponent, selector: "app-suffix", inputs: ["suffixConfig", "formId"] }] }); }
|
|
4292
4555
|
}
|
|
4293
4556
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: SingleFileUploadComponent, decorators: [{
|
|
4294
4557
|
type: Component,
|
|
4295
|
-
args: [{ selector:
|
|
4558
|
+
args: [{ selector: "app-single-file-upload", standalone: true, imports: [...modules$1, ...zorroModules$1, ...components$1], providers: [
|
|
4296
4559
|
{
|
|
4297
4560
|
provide: NG_VALUE_ACCESSOR,
|
|
4298
4561
|
useExisting: forwardRef(() => SingleFileUploadComponent),
|
|
4299
4562
|
multi: true,
|
|
4300
4563
|
},
|
|
4301
|
-
], template: "<div class=\"d-flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (
|
|
4564
|
+
], template: "<div class=\"d-flex\">\r\n @if (modeSignal() === formModeEnum.View) {\r\n @if (viewMode() === viewModeEnum.form) {\r\n <input nz-input [value]=\"viewDisplayValue()\" class=\"modeView\" />\r\n }\r\n @if (viewMode() === viewModeEnum.text) {\r\n <span class=\"modeView\">{{ viewDisplayValue() }}</span>\r\n }\r\n }\r\n @if (isAddOrEdit()) {\r\n <div class=\"flex w-100\">\r\n <nz-input-group\r\n [nzSuffix]=\"\r\n uploading() || (allFiles().length > 0 && isAddOrEdit())\r\n ? actionIcon\r\n : undefined\r\n \"\r\n class=\"flex-1\"\r\n >\r\n <input\r\n nz-input\r\n [value]=\"\r\n uploading() ? '\u0110ang t\u1EA3i l\u00EAn t\u1EADp tin...' : addEditDisplayValue()\r\n \"\r\n class=\"no-events\"\r\n />\r\n </nz-input-group>\r\n\r\n <nz-upload\r\n [nzShowUploadList]=\"false\"\r\n [nzMultiple]=\"false\"\r\n [nzBeforeUpload]=\"beforeUpload\"\r\n [nzCustomRequest]=\"customRequest\"\r\n >\r\n <button\r\n nz-button\r\n class=\"btn-upload h-100 text-white\"\r\n [disabled]=\"uploading()\"\r\n >\r\n <span class=\"fs-12\">T\u1EA3i l\u00EAn</span>\r\n <nz-icon nzType=\"upload\" nzTheme=\"outline\" />\r\n </button>\r\n </nz-upload>\r\n </div>\r\n }\r\n\r\n @if (field().suffixes.length > 0) {\r\n @for (suffix of field().suffixes; track $index) {\r\n @if (suffix.visibleOn?.includes(this.modeSignal())) {\r\n <app-suffix [suffixConfig]=\"suffix\" [formId]=\"formId\"> </app-suffix>\r\n }\r\n }\r\n }\r\n</div>\r\n\r\n<ng-template #actionIcon>\r\n @if (uploading()) {\r\n <span\r\n nz-icon\r\n nzType=\"loading\"\r\n nzTheme=\"outline\"\r\n class=\"text-primary\"\r\n ></span>\r\n } @else if (allFiles().length > 0 && isAddOrEdit()) {\r\n <span\r\n title=\"X\u00F3a\"\r\n class=\"mdi mdi-delete pointer text-danger\"\r\n (click)=\"handleDelete(allFiles()[0])\"\r\n ></span>\r\n }\r\n</ng-template>\r\n\r\n@if (field().showAcceptedExtensionGuide && fileExtensionGuide()) {\r\n <div class=\"file-extension-guide\">{{ fileExtensionGuide() }}</div>\r\n}\r\n\r\n<!-- Custom hi\u1EC3n th\u1ECB danh s\u00E1ch t\u1EADp tin -->\r\n<!-- @if (allFiles().length > 0) { -->\r\n<!-- <ng-container *ngTemplateOutlet=\"renderFileTpl\"></ng-container> -->\r\n<!-- } -->\r\n\r\n<!-- Template custom hi\u1EC3n th\u1ECB danh s\u00E1ch t\u1EADp tin -->\r\n<!-- <ng-template #renderFileTpl>\r\n <ul class=\"custom-upload-list\">\r\n @for (file of allFiles() | slice: 0 : 1; track file.objStorage?.id) {\r\n <li class=\"upload-item\">\r\n <span nz-icon nzType=\"paper-clip\" nzTheme=\"outline\" class=\"paper-clip-icon\"></span>\r\n\r\n <span class=\"filename\">{{ file.objStorage.name }}</span>\r\n\r\n @if (isAddOrEdit()) {\r\n <span\r\n nz-icon\r\n nzType=\"delete\"\r\n nzTheme=\"outline\"\r\n title=\"X\u00F3a\"\r\n class=\"delete-icon\"\r\n (click)=\"handleDelete(file)\"\r\n ></span>\r\n }\r\n </li>\r\n }\r\n </ul>\r\n</ng-template> -->\r\n", styles: [".file-extension-guide{font-size:11px;margin-top:8px;font-style:italic;color:#0f766e}.custom-upload-list{margin-top:.625rem;list-style-type:none;padding-inline-start:10px}.custom-upload-list .paper-clip-icon{margin-right:.5rem}.custom-upload-list .delete-icon{color:red;cursor:pointer;margin-left:.5rem}.file-name:hover{text-decoration:underline;color:#0a4c9f;cursor:pointer}.btn-upload{background-color:#2666ab}.no-events{pointer-events:none;color:#cdbfbf}\n"] }]
|
|
4302
4565
|
}], ctorParameters: () => [] });
|
|
4303
4566
|
|
|
4304
4567
|
// Các field component đại diện cho giao diện của từng control.
|
|
4305
4568
|
const FIELD_COMPONENTS = [
|
|
4306
4569
|
InputTextComponent,
|
|
4307
4570
|
InputPasswordComponent,
|
|
4571
|
+
InputFormattedComponent,
|
|
4308
4572
|
SingleSelectComponent,
|
|
4309
4573
|
MultiSelectComponent,
|
|
4310
4574
|
TreeSelectComponent,
|
|
@@ -4348,8 +4612,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
4348
4612
|
}]
|
|
4349
4613
|
}], ctorParameters: () => [] });
|
|
4350
4614
|
|
|
4351
|
-
|
|
4352
|
-
|
|
4615
|
+
class FieldUserConfigComponent {
|
|
4616
|
+
constructor() {
|
|
4617
|
+
this.field = input.required();
|
|
4618
|
+
this.control = input.required();
|
|
4619
|
+
}
|
|
4620
|
+
onToggleUserRequired(isRequired) {
|
|
4621
|
+
this.field().required = isRequired;
|
|
4622
|
+
const ctrl = this.control();
|
|
4623
|
+
if (isRequired) {
|
|
4624
|
+
ctrl.addValidators(Validators.required);
|
|
4625
|
+
}
|
|
4626
|
+
else {
|
|
4627
|
+
ctrl.removeValidators(Validators.required);
|
|
4628
|
+
}
|
|
4629
|
+
// Cập nhật lại trạng thái validation ngay lập tức
|
|
4630
|
+
ctrl.updateValueAndValidity();
|
|
4631
|
+
}
|
|
4632
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FieldUserConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4633
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: FieldUserConfigComponent, isStandalone: true, selector: "app-field-user-config", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<!-- C\u1EA5u h\u00ECnh (Dropdown & Menu) ch\u1EC9 hi\u1EC7n khi c\u00F3 b\u1EA5t k\u1EF3 config n\u00E0o -->\r\n@if (field().userConfigs) {\r\n <!-- Trigger N\u00FAt C\u1EA5u h\u00ECnh -->\r\n <a\r\n nz-dropdown\r\n [nzDropdownMenu]=\"configMenu\"\r\n nzTrigger=\"click\"\r\n [nzClickHide]=\"false\"\r\n [title]=\"'C\u1EA5u h\u00ECnh'\"\r\n nzPlacement=\"bottomRight\"\r\n >\r\n <span\r\n nz-icon\r\n nzType=\"setting\"\r\n nzTheme=\"outline\"\r\n class=\"config-trigger-icon\"\r\n ></span>\r\n </a>\r\n\r\n <!-- Menu C\u1EA5u h\u00ECnh -->\r\n <nz-dropdown-menu #configMenu=\"nzDropdownMenu\">\r\n <ul nz-menu>\r\n @if (field().userConfigs?.allowOverrideRequired) {\r\n <li nz-menu-item nzDisableItemHover class=\"config-menu-item\">\r\n <div class=\"config-item-content\">\r\n <span class=\"config-item-label\">B\u1EAFt bu\u1ED9c nh\u1EADp</span>\r\n <nz-switch\r\n nzSize=\"small\"\r\n [ngModel]=\"field().required\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n (ngModelChange)=\"onToggleUserRequired($event)\"\r\n ></nz-switch>\r\n </div>\r\n </li>\r\n }\r\n </ul>\r\n </nz-dropdown-menu>\r\n}\r\n", styles: ["@charset \"UTF-8\";.config-trigger-icon{color:#bfbfbf;cursor:pointer;font-size:16px;transition:all .3s cubic-bezier(.645,.045,.355,1);display:inline-block}.config-trigger-icon:hover{color:#1890ff;transform:rotate(90deg) scale(1.1)}.config-menu-item{padding:8px 12px;cursor:default}.config-item-content{display:flex;justify-content:space-between;align-items:center;gap:16px;min-width:130px}.config-item-label{font-size:13px}\n"], dependencies: [{ kind: "ngmodule", type: NzDropDownModule }, { kind: "directive", type: i1$3.NzMenuDirective, selector: "[nz-menu]", inputs: ["nzInlineIndent", "nzTheme", "nzMode", "nzInlineCollapsed", "nzSelectable"], outputs: ["nzClick"], exportAs: ["nzMenu"] }, { kind: "component", type: i1$3.NzMenuItemComponent, selector: "[nz-menu-item]", inputs: ["nzPaddingLeft", "nzDisabled", "nzSelected", "nzDanger", "nzMatchRouterExact", "nzMatchRouter"], exportAs: ["nzMenuItem"] }, { kind: "directive", type: i2$3.NzDropDownDirective, selector: "[nz-dropdown]", inputs: ["nzDropdownMenu", "nzTrigger", "nzMatchWidthElement", "nzBackdrop", "nzClickHide", "nzDisabled", "nzVisible", "nzOverlayClassName", "nzOverlayStyle", "nzPlacement"], outputs: ["nzVisibleChange"], exportAs: ["nzDropdown"] }, { kind: "directive", type: i2$3.NzDropDownADirective, selector: "a[nz-dropdown]" }, { kind: "component", type: i2$3.NzDropdownMenuComponent, selector: "nz-dropdown-menu", exportAs: ["nzDropdownMenu"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzSwitchModule }, { kind: "component", type: i4$1.NzSwitchComponent, selector: "nz-switch", inputs: ["nzLoading", "nzDisabled", "nzControl", "nzCheckedChildren", "nzUnCheckedChildren", "nzSize", "nzId"], exportAs: ["nzSwitch"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
|
|
4634
|
+
}
|
|
4635
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FieldUserConfigComponent, decorators: [{
|
|
4636
|
+
type: Component,
|
|
4637
|
+
args: [{ selector: "app-field-user-config", standalone: true, imports: [NzDropDownModule, NzIconModule, NzSwitchModule, FormsModule], template: "<!-- C\u1EA5u h\u00ECnh (Dropdown & Menu) ch\u1EC9 hi\u1EC7n khi c\u00F3 b\u1EA5t k\u1EF3 config n\u00E0o -->\r\n@if (field().userConfigs) {\r\n <!-- Trigger N\u00FAt C\u1EA5u h\u00ECnh -->\r\n <a\r\n nz-dropdown\r\n [nzDropdownMenu]=\"configMenu\"\r\n nzTrigger=\"click\"\r\n [nzClickHide]=\"false\"\r\n [title]=\"'C\u1EA5u h\u00ECnh'\"\r\n nzPlacement=\"bottomRight\"\r\n >\r\n <span\r\n nz-icon\r\n nzType=\"setting\"\r\n nzTheme=\"outline\"\r\n class=\"config-trigger-icon\"\r\n ></span>\r\n </a>\r\n\r\n <!-- Menu C\u1EA5u h\u00ECnh -->\r\n <nz-dropdown-menu #configMenu=\"nzDropdownMenu\">\r\n <ul nz-menu>\r\n @if (field().userConfigs?.allowOverrideRequired) {\r\n <li nz-menu-item nzDisableItemHover class=\"config-menu-item\">\r\n <div class=\"config-item-content\">\r\n <span class=\"config-item-label\">B\u1EAFt bu\u1ED9c nh\u1EADp</span>\r\n <nz-switch\r\n nzSize=\"small\"\r\n [ngModel]=\"field().required\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n (ngModelChange)=\"onToggleUserRequired($event)\"\r\n ></nz-switch>\r\n </div>\r\n </li>\r\n }\r\n </ul>\r\n </nz-dropdown-menu>\r\n}\r\n", styles: ["@charset \"UTF-8\";.config-trigger-icon{color:#bfbfbf;cursor:pointer;font-size:16px;transition:all .3s cubic-bezier(.645,.045,.355,1);display:inline-block}.config-trigger-icon:hover{color:#1890ff;transform:rotate(90deg) scale(1.1)}.config-menu-item{padding:8px 12px;cursor:default}.config-item-content{display:flex;justify-content:space-between;align-items:center;gap:16px;min-width:130px}.config-item-label{font-size:13px}\n"] }]
|
|
4638
|
+
}] });
|
|
4639
|
+
|
|
4640
|
+
const modules = [CommonModule, FormsModule, ReactiveFormsModule];
|
|
4641
|
+
const zorroModules = [
|
|
4642
|
+
NzFormModule,
|
|
4643
|
+
NzGridModule,
|
|
4644
|
+
NzDropDownModule,
|
|
4645
|
+
NzIconModule,
|
|
4646
|
+
NzSwitchModule,
|
|
4647
|
+
NzFlexModule,
|
|
4648
|
+
];
|
|
4649
|
+
const components = [...FIELD_COMPONENTS, FieldUserConfigComponent];
|
|
4353
4650
|
class DynamicFieldComponent {
|
|
4354
4651
|
constructor() {
|
|
4355
4652
|
this.field = input.required();
|
|
@@ -4369,11 +4666,11 @@ class DynamicFieldComponent {
|
|
|
4369
4666
|
return (this.validationService.getFirstError(this.control(), this.field(), this.fields()) ?? "");
|
|
4370
4667
|
}
|
|
4371
4668
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4372
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: DynamicFieldComponent, isStandalone: true, selector: "app-dynamic-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: true, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: true, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: true, transformFunction: null }, formId: { classPropertyName: "formId", publicName: "formId", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div [formGroup]=\"formGroup()\">\r\n <nz-form-item>\r\n <nz-form-label\r\n [nzXXl]=\"field().labelGrid.xxl ?? null\"\r\n [nzXl]=\"field().labelGrid.xl ?? null\"\r\n [nzLg]=\"field().labelGrid.lg ?? null\"\r\n [nzMd]=\"field().labelGrid.md ?? null\"\r\n [nzSm]=\"field().labelGrid.sm ?? null\"\r\n [nzXs]=\"field().labelGrid.xs ?? null\"\r\n [nzLabelAlign]=\"field().labelAlign\"\r\n >\r\n @if (field().required) {\r\n <span class=\"required\">*</span>\r\n }\r\n <span class=\"form-label\">\r\n {{ field().label }}\r\n @if (field().sublabel) {\r\n <span class=\"sub-label mb-sm\">{{ field().sublabel }}</span>\r\n }\r\n </span>\r\n </nz-form-label>\r\n\r\n <nz-form-control\r\n [nzXXl]=\"field().controlGrid.xxl ?? null\"\r\n [nzXl]=\"field().controlGrid.xl ?? null\"\r\n [nzLg]=\"field().controlGrid.lg ?? null\"\r\n [nzMd]=\"field().controlGrid.md ?? null\"\r\n [nzSm]=\"field().controlGrid.sm ?? null\"\r\n [nzXs]=\"field().controlGrid.xs ?? null\"\r\n [nzErrorTip]=\"getErrorMessage()\"\r\n >\r\n @switch (field().type) {\r\n <!-- Input text -->\r\n @case (fieldTypeEnum.InputText) {\r\n <app-input-text\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-input-text>\r\n }\r\n\r\n <!-- Input password -->\r\n @case (fieldTypeEnum.InputPassword) {\r\n @if (mode() === formModeEnum.Add) {\r\n <app-input-password\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-input-password>\r\n }\r\n }\r\n\r\n <!-- Textarea -->\r\n @case (fieldTypeEnum.Textarea) {\r\n <app-textarea\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-textarea>\r\n }\r\n\r\n <!-- Single select -->\r\n @case (fieldTypeEnum.SingleSelect) {\r\n <app-single-select\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-single-select>\r\n }\r\n\r\n <!-- Multi select -->\r\n @case (fieldTypeEnum.MultiSelect) {\r\n <app-multi-select\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-multi-select>\r\n }\r\n\r\n @case (fieldTypeEnum.TreeSelect) {\r\n <app-tree-select\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-tree-select>\r\n }\r\n\r\n <!-- Date Picker -->\r\n @case (fieldTypeEnum.DatePicker) {\r\n <app-date-picker\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-date-picker>\r\n }\r\n\r\n <!-- Date Range -->\r\n @case (fieldTypeEnum.DateRange) {\r\n <app-date-range\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-date-range>\r\n }\r\n\r\n <!-- Single File Upload -->\r\n @case (fieldTypeEnum.SingleFileUpload) {\r\n <app-single-file-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-single-file-upload>\r\n }\r\n\r\n <!-- Multi File Upload -->\r\n @case (fieldTypeEnum.MultiFileUpload) {\r\n <app-multi-file-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-multi-file-upload>\r\n }\r\n\r\n <!-- Multi File Upload -->\r\n @case (fieldTypeEnum.MultiImageUpload) {\r\n <app-multi-image-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-multi-image-upload>\r\n }\r\n\r\n <!-- Avatar -->\r\n @case (fieldTypeEnum.AvatarUpload) {\r\n <app-avatar-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-avatar-upload>\r\n }\r\n\r\n <!-- Radio -->\r\n @case (fieldTypeEnum.Radio) {\r\n <span>Radio</span>\r\n }\r\n\r\n <!-- Checkbox -->\r\n @case (fieldTypeEnum.Checkbox) {\r\n <span>Checkbox</span>\r\n }\r\n\r\n <!-- Radio -->\r\n @case (fieldTypeEnum.Radio) {\r\n <span>Radio</span>\r\n }\r\n\r\n <!-- Switch -->\r\n @case (fieldTypeEnum.Switch) {\r\n <span>Switch</span>\r\n }\r\n\r\n <!-- Autocomplete -->\r\n @case (fieldTypeEnum.Autocomplete) {\r\n <span>Autocomplete</span>\r\n }\r\n }\r\n </nz-form-control>\r\n </nz-form-item>\r\n</div>\r\n", styles: [".required{color:red;font-weight:700;margin-right:4px}.form-label{white-space:normal!important;word-break:break-word;font-weight:500;font-size:12px}.sub-label{white-space:normal!important;word-break:break-word;font-size:11px;font-style:italic}:host ::ng-deep .ant-form-item{align-items:center}:host ::ng-deep .ant-form-item-label>label{display:inline-block!important}\n"], dependencies: [{ kind: "ngmodule", type: i1.FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: NzFormModule }, { kind: "directive", type: i2$3.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i2$3.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "component", type: i3$3.NzFormItemComponent, selector: "nz-form-item", exportAs: ["nzFormItem"] }, { kind: "component", type: i3$3.NzFormLabelComponent, selector: "nz-form-label", inputs: ["nzFor", "nzRequired", "nzNoColon", "nzTooltipTitle", "nzTooltipIcon", "nzLabelAlign", "nzLabelWrap"], exportAs: ["nzFormLabel"] }, { kind: "component", type: i3$3.NzFormControlComponent, selector: "nz-form-control", inputs: ["nzSuccessTip", "nzWarningTip", "nzErrorTip", "nzValidatingTip", "nzExtra", "nzAutoTips", "nzDisableAutoTips", "nzHasFeedback", "nzValidateStatus"], exportAs: ["nzFormControl"] }, { kind: "ngmodule", type: NzGridModule }, { kind: "component", type: InputTextComponent, selector: "app-input-text" }, { kind: "component", type: InputPasswordComponent, selector: "app-input-password" }, { kind: "component", type: SingleSelectComponent, selector: "app-single-select", inputs: ["isCustomInputText"] }, { kind: "component", type: MultiSelectComponent, selector: "app-multi-select" }, { kind: "component", type: TreeSelectComponent, selector: "app-tree-select", inputs: ["isCustomInputText"] }, { kind: "component", type: TextareaComponent, selector: "app-textarea" }, { kind: "component", type: DatePickerComponent, selector: "app-date-picker" }, { kind: "component", type: DateRangeComponent, selector: "app-date-range" }, { kind: "component", type: SingleFileUploadComponent, selector: "app-single-file-upload" }, { kind: "component", type: MultiFileUploadComponent, selector: "app-multi-file-upload" }, { kind: "component", type: MultiImageUploadComponent, selector: "app-multi-image-upload" }, { kind: "component", type: AvatarUploadComponent, selector: "app-avatar-upload", inputs: ["size"] }] }); }
|
|
4669
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: DynamicFieldComponent, isStandalone: true, selector: "app-dynamic-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: true, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: true, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: true, transformFunction: null }, formId: { classPropertyName: "formId", publicName: "formId", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div [formGroup]=\"formGroup()\">\r\n <nz-form-item>\r\n <nz-form-label\r\n [nzXXl]=\"field().labelGrid.xxl ?? null\"\r\n [nzXl]=\"field().labelGrid.xl ?? null\"\r\n [nzLg]=\"field().labelGrid.lg ?? null\"\r\n [nzMd]=\"field().labelGrid.md ?? null\"\r\n [nzSm]=\"field().labelGrid.sm ?? null\"\r\n [nzXs]=\"field().labelGrid.xs ?? null\"\r\n [nzLabelAlign]=\"field().labelAlign\"\r\n >\r\n @if (field().required) {\r\n <span class=\"required\">*</span>\r\n }\r\n <span class=\"form-label\">\r\n {{ field().label }}\r\n @if (field().sublabel) {\r\n <span class=\"sub-label mb-sm\">{{ field().sublabel }}</span>\r\n }\r\n </span>\r\n </nz-form-label>\r\n\r\n <nz-form-control\r\n [nzXXl]=\"field().controlGrid.xxl ?? null\"\r\n [nzXl]=\"field().controlGrid.xl ?? null\"\r\n [nzLg]=\"field().controlGrid.lg ?? null\"\r\n [nzMd]=\"field().controlGrid.md ?? null\"\r\n [nzSm]=\"field().controlGrid.sm ?? null\"\r\n [nzXs]=\"field().controlGrid.xs ?? null\"\r\n [nzErrorTip]=\"getErrorMessage()\"\r\n >\r\n <div nz-flex [nzAlign]=\"'flex-start'\" [nzGap]=\"8\" class=\"w-100\">\r\n <div class=\"flex-1 min-w-0\">\r\n @switch (field().type) {\r\n <!-- Input text -->\r\n @case (fieldTypeEnum.InputText) {\r\n <app-input-text\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-input-text>\r\n }\r\n\r\n <!-- Input password -->\r\n @case (fieldTypeEnum.InputPassword) {\r\n @if (mode() === formModeEnum.Add) {\r\n <app-input-password\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-input-password>\r\n }\r\n }\r\n\r\n <!-- Input formatted -->\r\n @case (fieldTypeEnum.InputFormatted) {\r\n <app-input-formatted\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-input-formatted>\r\n }\r\n\r\n <!-- Textarea -->\r\n @case (fieldTypeEnum.Textarea) {\r\n <app-textarea\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-textarea>\r\n }\r\n\r\n <!-- Single select -->\r\n @case (fieldTypeEnum.SingleSelect) {\r\n <app-single-select\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-single-select>\r\n }\r\n\r\n <!-- Multi select -->\r\n @case (fieldTypeEnum.MultiSelect) {\r\n <app-multi-select\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-multi-select>\r\n }\r\n\r\n @case (fieldTypeEnum.TreeSelect) {\r\n <app-tree-select\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-tree-select>\r\n }\r\n\r\n <!-- Date Picker -->\r\n @case (fieldTypeEnum.DatePicker) {\r\n <app-date-picker\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-date-picker>\r\n }\r\n\r\n <!-- Date Range -->\r\n @case (fieldTypeEnum.DateRange) {\r\n <app-date-range\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-date-range>\r\n }\r\n\r\n <!-- Single File Upload -->\r\n @case (fieldTypeEnum.SingleFileUpload) {\r\n <app-single-file-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-single-file-upload>\r\n }\r\n\r\n <!-- Multi File Upload -->\r\n @case (fieldTypeEnum.MultiFileUpload) {\r\n <app-multi-file-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-multi-file-upload>\r\n }\r\n\r\n <!-- Multi File Upload -->\r\n @case (fieldTypeEnum.MultiImageUpload) {\r\n <app-multi-image-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-multi-image-upload>\r\n }\r\n\r\n <!-- Avatar -->\r\n @case (fieldTypeEnum.AvatarUpload) {\r\n <app-avatar-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-avatar-upload>\r\n }\r\n\r\n <!-- Radio -->\r\n @case (fieldTypeEnum.Radio) {\r\n <span>Radio</span>\r\n }\r\n\r\n <!-- Checkbox -->\r\n @case (fieldTypeEnum.Checkbox) {\r\n <span>Checkbox</span>\r\n }\r\n\r\n <!-- Radio -->\r\n @case (fieldTypeEnum.Radio) {\r\n <span>Radio</span>\r\n }\r\n\r\n <!-- Switch -->\r\n @case (fieldTypeEnum.Switch) {\r\n <span>Switch</span>\r\n }\r\n\r\n <!-- Autocomplete -->\r\n @case (fieldTypeEnum.Autocomplete) {\r\n <span>Autocomplete</span>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- T\u00E1ch ph\u1EA7n c\u1EA5u h\u00ECnh ra Component ri\u00EAng -->\r\n @if (mode() !== formModeEnum.View) {\r\n <div class=\"field-user-config-ctn\">\r\n <app-field-user-config\r\n [field]=\"field()\"\r\n [control]=\"control()\"\r\n ></app-field-user-config>\r\n </div>\r\n }\r\n </div>\r\n </nz-form-control>\r\n </nz-form-item>\r\n</div>\r\n", styles: [".required{color:red;font-weight:700;margin-right:4px}.form-label{white-space:normal!important;word-break:break-word;font-weight:500;font-size:12px}.sub-label{white-space:normal!important;word-break:break-word;font-size:11px;font-style:italic}:host ::ng-deep .ant-form-item{align-items:center}:host ::ng-deep .ant-form-item-label>label{display:inline-block!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: NzFormModule }, { kind: "directive", type: i2$4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i2$4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "component", type: i3$3.NzFormItemComponent, selector: "nz-form-item", exportAs: ["nzFormItem"] }, { kind: "component", type: i3$3.NzFormLabelComponent, selector: "nz-form-label", inputs: ["nzFor", "nzRequired", "nzNoColon", "nzTooltipTitle", "nzTooltipIcon", "nzLabelAlign", "nzLabelWrap"], exportAs: ["nzFormLabel"] }, { kind: "component", type: i3$3.NzFormControlComponent, selector: "nz-form-control", inputs: ["nzSuccessTip", "nzWarningTip", "nzErrorTip", "nzValidatingTip", "nzExtra", "nzAutoTips", "nzDisableAutoTips", "nzHasFeedback", "nzValidateStatus"], exportAs: ["nzFormControl"] }, { kind: "ngmodule", type: NzGridModule }, { kind: "ngmodule", type: NzDropDownModule }, { kind: "ngmodule", type: NzIconModule }, { kind: "ngmodule", type: NzSwitchModule }, { kind: "ngmodule", type: NzFlexModule }, { kind: "directive", type: i4$2.NzFlexDirective, selector: "[nz-flex],nz-flex", inputs: ["nzVertical", "nzJustify", "nzAlign", "nzGap", "nzWrap", "nzFlex"], exportAs: ["nzFlex"] }, { kind: "component", type: InputTextComponent, selector: "app-input-text" }, { kind: "component", type: InputPasswordComponent, selector: "app-input-password" }, { kind: "component", type: InputFormattedComponent, selector: "app-input-formatted" }, { kind: "component", type: SingleSelectComponent, selector: "app-single-select", inputs: ["isCustomInputText"] }, { kind: "component", type: MultiSelectComponent, selector: "app-multi-select" }, { kind: "component", type: TreeSelectComponent, selector: "app-tree-select", inputs: ["isCustomInputText"] }, { kind: "component", type: TextareaComponent, selector: "app-textarea" }, { kind: "component", type: DatePickerComponent, selector: "app-date-picker" }, { kind: "component", type: DateRangeComponent, selector: "app-date-range" }, { kind: "component", type: SingleFileUploadComponent, selector: "app-single-file-upload" }, { kind: "component", type: MultiFileUploadComponent, selector: "app-multi-file-upload" }, { kind: "component", type: MultiImageUploadComponent, selector: "app-multi-image-upload" }, { kind: "component", type: AvatarUploadComponent, selector: "app-avatar-upload", inputs: ["size"] }, { kind: "component", type: FieldUserConfigComponent, selector: "app-field-user-config", inputs: ["field", "control"] }] }); }
|
|
4373
4670
|
}
|
|
4374
4671
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFieldComponent, decorators: [{
|
|
4375
4672
|
type: Component,
|
|
4376
|
-
args: [{ selector: "app-dynamic-field", standalone: true, imports: [...
|
|
4673
|
+
args: [{ selector: "app-dynamic-field", standalone: true, imports: [...modules, ...zorroModules, ...components], template: "<div [formGroup]=\"formGroup()\">\r\n <nz-form-item>\r\n <nz-form-label\r\n [nzXXl]=\"field().labelGrid.xxl ?? null\"\r\n [nzXl]=\"field().labelGrid.xl ?? null\"\r\n [nzLg]=\"field().labelGrid.lg ?? null\"\r\n [nzMd]=\"field().labelGrid.md ?? null\"\r\n [nzSm]=\"field().labelGrid.sm ?? null\"\r\n [nzXs]=\"field().labelGrid.xs ?? null\"\r\n [nzLabelAlign]=\"field().labelAlign\"\r\n >\r\n @if (field().required) {\r\n <span class=\"required\">*</span>\r\n }\r\n <span class=\"form-label\">\r\n {{ field().label }}\r\n @if (field().sublabel) {\r\n <span class=\"sub-label mb-sm\">{{ field().sublabel }}</span>\r\n }\r\n </span>\r\n </nz-form-label>\r\n\r\n <nz-form-control\r\n [nzXXl]=\"field().controlGrid.xxl ?? null\"\r\n [nzXl]=\"field().controlGrid.xl ?? null\"\r\n [nzLg]=\"field().controlGrid.lg ?? null\"\r\n [nzMd]=\"field().controlGrid.md ?? null\"\r\n [nzSm]=\"field().controlGrid.sm ?? null\"\r\n [nzXs]=\"field().controlGrid.xs ?? null\"\r\n [nzErrorTip]=\"getErrorMessage()\"\r\n >\r\n <div nz-flex [nzAlign]=\"'flex-start'\" [nzGap]=\"8\" class=\"w-100\">\r\n <div class=\"flex-1 min-w-0\">\r\n @switch (field().type) {\r\n <!-- Input text -->\r\n @case (fieldTypeEnum.InputText) {\r\n <app-input-text\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-input-text>\r\n }\r\n\r\n <!-- Input password -->\r\n @case (fieldTypeEnum.InputPassword) {\r\n @if (mode() === formModeEnum.Add) {\r\n <app-input-password\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-input-password>\r\n }\r\n }\r\n\r\n <!-- Input formatted -->\r\n @case (fieldTypeEnum.InputFormatted) {\r\n <app-input-formatted\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-input-formatted>\r\n }\r\n\r\n <!-- Textarea -->\r\n @case (fieldTypeEnum.Textarea) {\r\n <app-textarea\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-textarea>\r\n }\r\n\r\n <!-- Single select -->\r\n @case (fieldTypeEnum.SingleSelect) {\r\n <app-single-select\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-single-select>\r\n }\r\n\r\n <!-- Multi select -->\r\n @case (fieldTypeEnum.MultiSelect) {\r\n <app-multi-select\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-multi-select>\r\n }\r\n\r\n @case (fieldTypeEnum.TreeSelect) {\r\n <app-tree-select\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-tree-select>\r\n }\r\n\r\n <!-- Date Picker -->\r\n @case (fieldTypeEnum.DatePicker) {\r\n <app-date-picker\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-date-picker>\r\n }\r\n\r\n <!-- Date Range -->\r\n @case (fieldTypeEnum.DateRange) {\r\n <app-date-range\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-date-range>\r\n }\r\n\r\n <!-- Single File Upload -->\r\n @case (fieldTypeEnum.SingleFileUpload) {\r\n <app-single-file-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-single-file-upload>\r\n }\r\n\r\n <!-- Multi File Upload -->\r\n @case (fieldTypeEnum.MultiFileUpload) {\r\n <app-multi-file-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-multi-file-upload>\r\n }\r\n\r\n <!-- Multi File Upload -->\r\n @case (fieldTypeEnum.MultiImageUpload) {\r\n <app-multi-image-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-multi-image-upload>\r\n }\r\n\r\n <!-- Avatar -->\r\n @case (fieldTypeEnum.AvatarUpload) {\r\n <app-avatar-upload\r\n [formControlName]=\"field().key\"\r\n [fieldInput]=\"field()\"\r\n [modeSignal]=\"mode()\"\r\n [control]=\"control()\"\r\n [formId]=\"formId()\"\r\n ></app-avatar-upload>\r\n }\r\n\r\n <!-- Radio -->\r\n @case (fieldTypeEnum.Radio) {\r\n <span>Radio</span>\r\n }\r\n\r\n <!-- Checkbox -->\r\n @case (fieldTypeEnum.Checkbox) {\r\n <span>Checkbox</span>\r\n }\r\n\r\n <!-- Radio -->\r\n @case (fieldTypeEnum.Radio) {\r\n <span>Radio</span>\r\n }\r\n\r\n <!-- Switch -->\r\n @case (fieldTypeEnum.Switch) {\r\n <span>Switch</span>\r\n }\r\n\r\n <!-- Autocomplete -->\r\n @case (fieldTypeEnum.Autocomplete) {\r\n <span>Autocomplete</span>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- T\u00E1ch ph\u1EA7n c\u1EA5u h\u00ECnh ra Component ri\u00EAng -->\r\n @if (mode() !== formModeEnum.View) {\r\n <div class=\"field-user-config-ctn\">\r\n <app-field-user-config\r\n [field]=\"field()\"\r\n [control]=\"control()\"\r\n ></app-field-user-config>\r\n </div>\r\n }\r\n </div>\r\n </nz-form-control>\r\n </nz-form-item>\r\n</div>\r\n", styles: [".required{color:red;font-weight:700;margin-right:4px}.form-label{white-space:normal!important;word-break:break-word;font-weight:500;font-size:12px}.sub-label{white-space:normal!important;word-break:break-word;font-size:11px;font-style:italic}:host ::ng-deep .ant-form-item{align-items:center}:host ::ng-deep .ant-form-item-label>label{display:inline-block!important}\n"] }]
|
|
4377
4674
|
}] });
|
|
4378
4675
|
|
|
4379
4676
|
const ZORRO_MODULES = [NzFormModule, NzGridModule, NzCollapseModule];
|
|
@@ -4559,11 +4856,11 @@ class DynamicFormComponent {
|
|
|
4559
4856
|
return field.key || `field-${index}`;
|
|
4560
4857
|
}
|
|
4561
4858
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormComponent, deps: [{ token: DynamicFormService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4562
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: DynamicFormComponent, isStandalone: true, selector: "app-dynamic-forms", inputs: { formId: { classPropertyName: "formId", publicName: "formId", isSignal: false, isRequired: false, transformFunction: null }, valueChangesDebounceTime: { classPropertyName: "valueChangesDebounceTime", publicName: "valueChangesDebounceTime", isSignal: false, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, fieldGroups: { classPropertyName: "fieldGroups", publicName: "fieldGroups", isSignal: true, isRequired: false, transformFunction: null }, displayNonGroupedFields: { classPropertyName: "displayNonGroupedFields", publicName: "displayNonGroupedFields", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formValueChanges: "formValueChanges", formSubmit: "formSubmit", formInvalid: "formInvalid" }, ngImport: i0, template: "@if (formGroup) {\r\n <form [formGroup]=\"formGroup\">\r\n @if (oldFields().length > 0) {\r\n <!-- 1. N\u1EBFu kh\u00F4ng c\u00F3 groups th\u00EC render t\u1EEB fields -->\r\n @if (!fieldGroups() || fieldGroups().length === 0) {\r\n <div nz-row [nzGutter]=\"[12, 0]\">\r\n @for (field of oldFields(); track field?.id) {\r\n @if (!isHiddenField(field)) {\r\n <div\r\n nz-col\r\n [nzXXl]=\"field?.grid?.xxl ?? null\"\r\n [nzXl]=\"field?.grid?.xl ?? null\"\r\n [nzLg]=\"field?.grid?.lg ?? null\"\r\n [nzMd]=\"field?.grid?.md ?? null\"\r\n [nzSm]=\"field?.grid?.sm ?? null\"\r\n [nzXs]=\"field?.grid?.xs ?? null\"\r\n [nzFlex]=\"\r\n !field?.grid?.xs &&\r\n !field?.grid?.sm &&\r\n !field?.grid?.md &&\r\n !field?.grid?.lg &&\r\n !field?.grid?.xl &&\r\n !field?.grid?.xxl\r\n ? '1 0 0'\r\n : null\r\n \"\r\n class=\"field\"\r\n >\r\n <app-dynamic-field\r\n [field]=\"field\"\r\n [fields]=\"oldFields()\"\r\n [mode]=\"mode()\"\r\n [control]=\"formGroup.get(field.key)!\"\r\n [formGroup]=\"formGroup\"\r\n [formId]=\"formId\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- 2. N\u1EBFu c\u00F3 groups th\u00EC render t\u1EEB groupedFields -->\r\n @if (fieldGroups() && fieldGroups().length > 0) {\r\n <!-- C\u00E1c field noGroup -->\r\n @if (groupedFields().noGroup.length > 0 && displayNonGroupedFields()) {\r\n <div nz-row [nzGutter]=\"24\">\r\n @for (field of groupedFields().noGroup; track field?.id) {\r\n @if (!isHiddenField(field)) {\r\n <div\r\n nz-col\r\n [nzXXl]=\"field?.grid?.xxl ?? null\"\r\n [nzXl]=\"field?.grid?.xl ?? null\"\r\n [nzLg]=\"field?.grid?.lg ?? null\"\r\n [nzMd]=\"field?.grid?.md ?? null\"\r\n [nzSm]=\"field?.grid?.sm ?? null\"\r\n [nzXs]=\"field?.grid?.xs ?? null\"\r\n class=\"field\"\r\n >\r\n <app-dynamic-field\r\n [field]=\"field\"\r\n [fields]=\"oldFields()\"\r\n [mode]=\"mode()\"\r\n [control]=\"formGroup.get(field.key)!\"\r\n [formGroup]=\"formGroup\"\r\n [formId]=\"formId\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Group c\u00E1c field -->\r\n @if (groupedFields().grouped.length > 0) {\r\n <nz-collapse [nzBordered]=\"false\">\r\n @for (groupField of groupedFields().grouped
|
|
4859
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: DynamicFormComponent, isStandalone: true, selector: "app-dynamic-forms", inputs: { formId: { classPropertyName: "formId", publicName: "formId", isSignal: false, isRequired: false, transformFunction: null }, valueChangesDebounceTime: { classPropertyName: "valueChangesDebounceTime", publicName: "valueChangesDebounceTime", isSignal: false, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, fieldGroups: { classPropertyName: "fieldGroups", publicName: "fieldGroups", isSignal: true, isRequired: false, transformFunction: null }, displayNonGroupedFields: { classPropertyName: "displayNonGroupedFields", publicName: "displayNonGroupedFields", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formValueChanges: "formValueChanges", formSubmit: "formSubmit", formInvalid: "formInvalid" }, ngImport: i0, template: "@if (formGroup) {\r\n <form [formGroup]=\"formGroup\">\r\n @if (oldFields().length > 0) {\r\n <!-- 1. N\u1EBFu kh\u00F4ng c\u00F3 groups th\u00EC render t\u1EEB fields -->\r\n @if (!fieldGroups() || fieldGroups().length === 0) {\r\n <div nz-row [nzGutter]=\"[12, 0]\">\r\n @for (field of oldFields(); track field?.id) {\r\n @if (!isHiddenField(field)) {\r\n <div\r\n nz-col\r\n [nzXXl]=\"field?.grid?.xxl ?? null\"\r\n [nzXl]=\"field?.grid?.xl ?? null\"\r\n [nzLg]=\"field?.grid?.lg ?? null\"\r\n [nzMd]=\"field?.grid?.md ?? null\"\r\n [nzSm]=\"field?.grid?.sm ?? null\"\r\n [nzXs]=\"field?.grid?.xs ?? null\"\r\n [nzFlex]=\"\r\n !field?.grid?.xs &&\r\n !field?.grid?.sm &&\r\n !field?.grid?.md &&\r\n !field?.grid?.lg &&\r\n !field?.grid?.xl &&\r\n !field?.grid?.xxl\r\n ? '1 0 0'\r\n : null\r\n \"\r\n class=\"field\"\r\n >\r\n <app-dynamic-field\r\n [field]=\"field\"\r\n [fields]=\"oldFields()\"\r\n [mode]=\"mode()\"\r\n [control]=\"formGroup.get(field.key)!\"\r\n [formGroup]=\"formGroup\"\r\n [formId]=\"formId\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- 2. N\u1EBFu c\u00F3 groups th\u00EC render t\u1EEB groupedFields -->\r\n @if (fieldGroups() && fieldGroups().length > 0) {\r\n <!-- C\u00E1c field noGroup -->\r\n @if (groupedFields().noGroup.length > 0 && displayNonGroupedFields()) {\r\n <div nz-row [nzGutter]=\"24\">\r\n @for (field of groupedFields().noGroup; track field?.id) {\r\n @if (!isHiddenField(field)) {\r\n <div\r\n nz-col\r\n [nzXXl]=\"field?.grid?.xxl ?? null\"\r\n [nzXl]=\"field?.grid?.xl ?? null\"\r\n [nzLg]=\"field?.grid?.lg ?? null\"\r\n [nzMd]=\"field?.grid?.md ?? null\"\r\n [nzSm]=\"field?.grid?.sm ?? null\"\r\n [nzXs]=\"field?.grid?.xs ?? null\"\r\n class=\"field\"\r\n >\r\n <app-dynamic-field\r\n [field]=\"field\"\r\n [fields]=\"oldFields()\"\r\n [mode]=\"mode()\"\r\n [control]=\"formGroup.get(field.key)!\"\r\n [formGroup]=\"formGroup\"\r\n [formId]=\"formId\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Group c\u00E1c field -->\r\n @if (groupedFields().grouped.length > 0) {\r\n <nz-collapse [nzBordered]=\"false\">\r\n @for (\r\n groupField of groupedFields().grouped;\r\n track groupField.group.code\r\n ) {\r\n <nz-collapse-panel\r\n [nzHeader]=\"groupField.group.template ?? groupField.group.label\"\r\n [nzActive]=\"groupField.group.isActive\"\r\n [nzShowArrow]=\"groupField.group.showArrow\"\r\n [nzDisabled]=\"groupField.group.disabled\"\r\n [style]=\"collapseCustomStyle\"\r\n class=\"mt-sm\"\r\n >\r\n <div nz-row [nzGutter]=\"24\">\r\n @for (field of groupField.fields; track field?.id) {\r\n @if (!isHiddenField(field)) {\r\n <div\r\n nz-col\r\n [nzXXl]=\"field?.grid?.xxl ?? null\"\r\n [nzXl]=\"field?.grid?.xl ?? null\"\r\n [nzLg]=\"field?.grid?.lg ?? null\"\r\n [nzMd]=\"field?.grid?.md ?? null\"\r\n [nzSm]=\"field?.grid?.sm ?? null\"\r\n [nzXs]=\"field?.grid?.xs ?? null\"\r\n class=\"field\"\r\n >\r\n <app-dynamic-field\r\n [field]=\"field\"\r\n [fields]=\"oldFields()\"\r\n [mode]=\"mode()\"\r\n [control]=\"formGroup.get(field.key)!\"\r\n [formGroup]=\"formGroup\"\r\n [formId]=\"formId\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n </nz-collapse-panel>\r\n }\r\n </nz-collapse>\r\n }\r\n }\r\n }\r\n </form>\r\n}\r\n", styles: [":host ::ng-deep .ant-collapse .ant-collapse-item-disabled>.ant-collapse-header,:host ::ng-deep .ant-collapse .ant-collapse-item-disabled>.ant-collapse-header>.arrow{color:#575757;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: i1.FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: i1.ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: NzFormModule }, { kind: "directive", type: i2$4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i2$4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "ngmodule", type: NzGridModule }, { kind: "ngmodule", type: NzCollapseModule }, { kind: "component", type: i4$3.NzCollapsePanelComponent, selector: "nz-collapse-panel", inputs: ["nzActive", "nzDisabled", "nzShowArrow", "nzExtra", "nzHeader", "nzExpandedIcon"], outputs: ["nzActiveChange"], exportAs: ["nzCollapsePanel"] }, { kind: "component", type: i4$3.NzCollapseComponent, selector: "nz-collapse", inputs: ["nzAccordion", "nzBordered", "nzGhost", "nzExpandIconPosition"], exportAs: ["nzCollapse"] }, { kind: "component", type: DynamicFieldComponent, selector: "app-dynamic-field", inputs: ["field", "fields", "mode", "control", "formGroup", "formId"] }] }); }
|
|
4563
4860
|
}
|
|
4564
4861
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormComponent, decorators: [{
|
|
4565
4862
|
type: Component,
|
|
4566
|
-
args: [{ selector: 'app-dynamic-forms', standalone: true, imports: [...FORM_MODULES, ...ZORRO_MODULES, ...COMPONENTS], template: "@if (formGroup) {\r\n <form [formGroup]=\"formGroup\">\r\n @if (oldFields().length > 0) {\r\n <!-- 1. N\u1EBFu kh\u00F4ng c\u00F3 groups th\u00EC render t\u1EEB fields -->\r\n @if (!fieldGroups() || fieldGroups().length === 0) {\r\n <div nz-row [nzGutter]=\"[12, 0]\">\r\n @for (field of oldFields(); track field?.id) {\r\n @if (!isHiddenField(field)) {\r\n <div\r\n nz-col\r\n [nzXXl]=\"field?.grid?.xxl ?? null\"\r\n [nzXl]=\"field?.grid?.xl ?? null\"\r\n [nzLg]=\"field?.grid?.lg ?? null\"\r\n [nzMd]=\"field?.grid?.md ?? null\"\r\n [nzSm]=\"field?.grid?.sm ?? null\"\r\n [nzXs]=\"field?.grid?.xs ?? null\"\r\n [nzFlex]=\"\r\n !field?.grid?.xs &&\r\n !field?.grid?.sm &&\r\n !field?.grid?.md &&\r\n !field?.grid?.lg &&\r\n !field?.grid?.xl &&\r\n !field?.grid?.xxl\r\n ? '1 0 0'\r\n : null\r\n \"\r\n class=\"field\"\r\n >\r\n <app-dynamic-field\r\n [field]=\"field\"\r\n [fields]=\"oldFields()\"\r\n [mode]=\"mode()\"\r\n [control]=\"formGroup.get(field.key)!\"\r\n [formGroup]=\"formGroup\"\r\n [formId]=\"formId\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- 2. N\u1EBFu c\u00F3 groups th\u00EC render t\u1EEB groupedFields -->\r\n @if (fieldGroups() && fieldGroups().length > 0) {\r\n <!-- C\u00E1c field noGroup -->\r\n @if (groupedFields().noGroup.length > 0 && displayNonGroupedFields()) {\r\n <div nz-row [nzGutter]=\"24\">\r\n @for (field of groupedFields().noGroup; track field?.id) {\r\n @if (!isHiddenField(field)) {\r\n <div\r\n nz-col\r\n [nzXXl]=\"field?.grid?.xxl ?? null\"\r\n [nzXl]=\"field?.grid?.xl ?? null\"\r\n [nzLg]=\"field?.grid?.lg ?? null\"\r\n [nzMd]=\"field?.grid?.md ?? null\"\r\n [nzSm]=\"field?.grid?.sm ?? null\"\r\n [nzXs]=\"field?.grid?.xs ?? null\"\r\n class=\"field\"\r\n >\r\n <app-dynamic-field\r\n [field]=\"field\"\r\n [fields]=\"oldFields()\"\r\n [mode]=\"mode()\"\r\n [control]=\"formGroup.get(field.key)!\"\r\n [formGroup]=\"formGroup\"\r\n [formId]=\"formId\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Group c\u00E1c field -->\r\n @if (groupedFields().grouped.length > 0) {\r\n <nz-collapse [nzBordered]=\"false\">\r\n @for (groupField of groupedFields().grouped
|
|
4863
|
+
args: [{ selector: 'app-dynamic-forms', standalone: true, imports: [...FORM_MODULES, ...ZORRO_MODULES, ...COMPONENTS], template: "@if (formGroup) {\r\n <form [formGroup]=\"formGroup\">\r\n @if (oldFields().length > 0) {\r\n <!-- 1. N\u1EBFu kh\u00F4ng c\u00F3 groups th\u00EC render t\u1EEB fields -->\r\n @if (!fieldGroups() || fieldGroups().length === 0) {\r\n <div nz-row [nzGutter]=\"[12, 0]\">\r\n @for (field of oldFields(); track field?.id) {\r\n @if (!isHiddenField(field)) {\r\n <div\r\n nz-col\r\n [nzXXl]=\"field?.grid?.xxl ?? null\"\r\n [nzXl]=\"field?.grid?.xl ?? null\"\r\n [nzLg]=\"field?.grid?.lg ?? null\"\r\n [nzMd]=\"field?.grid?.md ?? null\"\r\n [nzSm]=\"field?.grid?.sm ?? null\"\r\n [nzXs]=\"field?.grid?.xs ?? null\"\r\n [nzFlex]=\"\r\n !field?.grid?.xs &&\r\n !field?.grid?.sm &&\r\n !field?.grid?.md &&\r\n !field?.grid?.lg &&\r\n !field?.grid?.xl &&\r\n !field?.grid?.xxl\r\n ? '1 0 0'\r\n : null\r\n \"\r\n class=\"field\"\r\n >\r\n <app-dynamic-field\r\n [field]=\"field\"\r\n [fields]=\"oldFields()\"\r\n [mode]=\"mode()\"\r\n [control]=\"formGroup.get(field.key)!\"\r\n [formGroup]=\"formGroup\"\r\n [formId]=\"formId\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- 2. N\u1EBFu c\u00F3 groups th\u00EC render t\u1EEB groupedFields -->\r\n @if (fieldGroups() && fieldGroups().length > 0) {\r\n <!-- C\u00E1c field noGroup -->\r\n @if (groupedFields().noGroup.length > 0 && displayNonGroupedFields()) {\r\n <div nz-row [nzGutter]=\"24\">\r\n @for (field of groupedFields().noGroup; track field?.id) {\r\n @if (!isHiddenField(field)) {\r\n <div\r\n nz-col\r\n [nzXXl]=\"field?.grid?.xxl ?? null\"\r\n [nzXl]=\"field?.grid?.xl ?? null\"\r\n [nzLg]=\"field?.grid?.lg ?? null\"\r\n [nzMd]=\"field?.grid?.md ?? null\"\r\n [nzSm]=\"field?.grid?.sm ?? null\"\r\n [nzXs]=\"field?.grid?.xs ?? null\"\r\n class=\"field\"\r\n >\r\n <app-dynamic-field\r\n [field]=\"field\"\r\n [fields]=\"oldFields()\"\r\n [mode]=\"mode()\"\r\n [control]=\"formGroup.get(field.key)!\"\r\n [formGroup]=\"formGroup\"\r\n [formId]=\"formId\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Group c\u00E1c field -->\r\n @if (groupedFields().grouped.length > 0) {\r\n <nz-collapse [nzBordered]=\"false\">\r\n @for (\r\n groupField of groupedFields().grouped;\r\n track groupField.group.code\r\n ) {\r\n <nz-collapse-panel\r\n [nzHeader]=\"groupField.group.template ?? groupField.group.label\"\r\n [nzActive]=\"groupField.group.isActive\"\r\n [nzShowArrow]=\"groupField.group.showArrow\"\r\n [nzDisabled]=\"groupField.group.disabled\"\r\n [style]=\"collapseCustomStyle\"\r\n class=\"mt-sm\"\r\n >\r\n <div nz-row [nzGutter]=\"24\">\r\n @for (field of groupField.fields; track field?.id) {\r\n @if (!isHiddenField(field)) {\r\n <div\r\n nz-col\r\n [nzXXl]=\"field?.grid?.xxl ?? null\"\r\n [nzXl]=\"field?.grid?.xl ?? null\"\r\n [nzLg]=\"field?.grid?.lg ?? null\"\r\n [nzMd]=\"field?.grid?.md ?? null\"\r\n [nzSm]=\"field?.grid?.sm ?? null\"\r\n [nzXs]=\"field?.grid?.xs ?? null\"\r\n class=\"field\"\r\n >\r\n <app-dynamic-field\r\n [field]=\"field\"\r\n [fields]=\"oldFields()\"\r\n [mode]=\"mode()\"\r\n [control]=\"formGroup.get(field.key)!\"\r\n [formGroup]=\"formGroup\"\r\n [formId]=\"formId\"\r\n />\r\n </div>\r\n }\r\n }\r\n </div>\r\n </nz-collapse-panel>\r\n }\r\n </nz-collapse>\r\n }\r\n }\r\n }\r\n </form>\r\n}\r\n", styles: [":host ::ng-deep .ant-collapse .ant-collapse-item-disabled>.ant-collapse-header,:host ::ng-deep .ant-collapse .ant-collapse-item-disabled>.ant-collapse-header>.arrow{color:#575757;cursor:not-allowed}\n"] }]
|
|
4567
4864
|
}], ctorParameters: () => [{ type: DynamicFormService }], propDecorators: { formId: [{
|
|
4568
4865
|
type: Input
|
|
4569
4866
|
}], valueChangesDebounceTime: [{
|
|
@@ -4637,5 +4934,5 @@ class RadioBaseField extends BaseField {
|
|
|
4637
4934
|
* Generated bundle index. Do not edit.
|
|
4638
4935
|
*/
|
|
4639
4936
|
|
|
4640
|
-
export { ALL_MIME_TYPES, ALL_MIME_TYPES_VALUE, APPLICATION_TYPES, AUDIO_TYPES, AvatarUploadField, BaseDateField, BaseField, BaseUploadField, CombineDependTypeEnum, CommonValidaterEnum, ControlTypeEnum, CustomValidaterEnum, DEFAULT_ACCEPTED_IMAGE_MIME_TYPES, DEFAULT_ACCEPTED_MIME_TYPES, DYNAMIC_FORM_CONFIG, DateFieldTypeEnum, DatePickerField, DatePickerOutputValueTypeEnum, DateRangeField, DateRangeOutputValueTypeEnum, DependTypeEnum, DynamicFormComponent, DynamicFormService, FieldGroup, FieldTypeEnum, FileService, FileSizeTypeEnum, FormConfigService, FormDataService, FormModeEnum, GroupedFields, IMAGE_TYPES, InputBaseField, InputFieldTypeEnum, InputPasswordField, InputTextField, MIME_TYPES_TO_EXTENSION, MultiFileUploadField, MultiImageUploadField, MultiSelectField, RadioBaseField, SelectBaseField, SelectFieldTypeEnum, SelectOutputValueTypeEnum, SingleFileUploadField, SingleSelectField, SuffixService, TEXT_TYPES, TableCellTypeEnum, TextareaField,
|
|
4937
|
+
export { ALL_MIME_TYPES, ALL_MIME_TYPES_VALUE, APPLICATION_TYPES, AUDIO_TYPES, AvatarUploadField, BaseDateField, BaseField, BaseUploadField, CombineDependTypeEnum, CommonValidaterEnum, ControlTypeEnum, CustomValidaterEnum, DEFAULT_ACCEPTED_IMAGE_MIME_TYPES, DEFAULT_ACCEPTED_MIME_TYPES, DYNAMIC_FORM_CONFIG, DateFieldTypeEnum, DatePickerField, DatePickerOutputValueTypeEnum, DateRangeField, DateRangeOutputValueTypeEnum, DependTypeEnum, DynamicFormComponent, DynamicFormService, FieldGroup, FieldTypeEnum, FileService, FileSizeTypeEnum, FormConfigService, FormDataService, FormModeEnum, GroupedFields, IMAGE_TYPES, InputBaseField, InputFieldTypeEnum, InputFormattedField, InputPasswordField, InputTextField, MIME_TYPES_TO_EXTENSION, MultiFileUploadField, MultiImageUploadField, MultiSelectField, NumericPreset, RadioBaseField, RegexTypeEnum, SelectBaseField, SelectFieldTypeEnum, SelectOutputValueTypeEnum, SingleFileUploadField, SingleSelectField, SuffixService, TEXT_TYPES, TableCellTypeEnum, TextareaField, UploadFieldTypeEnum, UploadOutputValueTypeEnum, VIDEO_TYPES, ViewModeEnum, videoTypesPath };
|
|
4641
4938
|
//# sourceMappingURL=ldquocc-dynamic-form.mjs.map
|