@ldquocc/dynamic-form 0.0.2 → 0.0.4
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.
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, Injectable, signal, untracked, input, computed, Input, Directive, effect, forwardRef, Component, EventEmitter, output, Output } from '@angular/core';
|
|
3
1
|
import * as i1 from '@angular/forms';
|
|
4
2
|
import { FormsModule, ReactiveFormsModule, FormControl, Validators, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
5
3
|
import { of, delay, Subject, takeUntil, finalize, Observable, debounceTime, distinctUntilChanged } from 'rxjs';
|
|
6
4
|
import * as i1$2 from '@angular/common';
|
|
7
5
|
import { CommonModule, CurrencyPipe } from '@angular/common';
|
|
8
6
|
import { RouterModule } from '@angular/router';
|
|
7
|
+
import * as i0 from '@angular/core';
|
|
8
|
+
import { InjectionToken, inject, Injectable, signal, untracked, input, computed, Input, Directive, effect, forwardRef, Component, 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';
|
|
@@ -42,14 +42,6 @@ import { NzGridModule } from 'ng-zorro-antd/grid';
|
|
|
42
42
|
import * as i4$2 from 'ng-zorro-antd/collapse';
|
|
43
43
|
import { NzCollapseModule } from 'ng-zorro-antd/collapse';
|
|
44
44
|
|
|
45
|
-
var FormModeEnum;
|
|
46
|
-
(function (FormModeEnum) {
|
|
47
|
-
FormModeEnum["Add"] = "add";
|
|
48
|
-
FormModeEnum["Edit"] = "edit";
|
|
49
|
-
FormModeEnum["View"] = "view";
|
|
50
|
-
FormModeEnum["Design"] = "design";
|
|
51
|
-
})(FormModeEnum || (FormModeEnum = {}));
|
|
52
|
-
|
|
53
45
|
// Core Angular modules (cần thiết ở hầu hết các component).
|
|
54
46
|
const CORE_MODULES = [CommonModule];
|
|
55
47
|
// Form handling (thường dùng với Reactive)
|
|
@@ -568,6 +560,241 @@ class DateRangeField extends BaseDateField {
|
|
|
568
560
|
}
|
|
569
561
|
}
|
|
570
562
|
|
|
563
|
+
// Các patterns regex thường dùng trong ứng dụng
|
|
564
|
+
const PATTERN_PRESETS = {
|
|
565
|
+
alpha: '^[a-zA-Z]+$',
|
|
566
|
+
alphaNumeric: '^[a-zA-Z0-9]+$',
|
|
567
|
+
name: "^[0-9a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\\.+,:%&=;s.\\/\\-_'\\()]+$",
|
|
568
|
+
username: '^[a-z0-9_.s]+$',
|
|
569
|
+
regexPostCode: '^[a-zA-Z0-9-s]+$',
|
|
570
|
+
alphaDash: '^[a-zA-Z0-9_-s.]+$',
|
|
571
|
+
alphaVN: '^[a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\\,s]+$',
|
|
572
|
+
alphaNumericVN: '^[0-9a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\\s]+$',
|
|
573
|
+
alphaDashVN: "^[0-9a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\\.+,:%&=;s.\\/\\-_'\\()]+$",
|
|
574
|
+
unitName: '^[a-zA-Z0-9 ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵỷỹs_-]+$',
|
|
575
|
+
date: '([12]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01]))',
|
|
576
|
+
time: '(?=[01]\\d|2[0123])=(?=[012345]\\d)=(?=[012345]\\d)',
|
|
577
|
+
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]',
|
|
578
|
+
// dateV: "^(0?[1-9]|[12][0-9]|3[01])[\\/](0?[1-9]|1[012])[\\/]\\d{4}$",
|
|
579
|
+
// dateV: /^(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-](19|20)\d\d/,
|
|
580
|
+
// dateV: "^([0-2][0-9]|(3)[0-1])(\-)(((0)[0-9])|((1)[0-2]))(\-)\d{4}$",
|
|
581
|
+
dateVN: '^(?=0[1-9]|[12]d|3[01])([/.-])(?=0[1-9]|1[012])\\1(?=19|20)dd$',
|
|
582
|
+
dateTimeVN: '^(0?[1-9]|[12][0-9]|3[01])[\\/](0?[1-9]|1[012])[\\/]\\d{4} (\\d{2})=(\\d{2})=(\\d{2})$',
|
|
583
|
+
dateShortTimeVN: '^(0?[1-9]|[12][0-9]|3[01])[\\/](0?[1-9]|1[012])[\\/]\\d{4} (\\d{2})=(\\d{2})$',
|
|
584
|
+
integer: '^\\-?[0-9]+$',
|
|
585
|
+
decimal: '^\\-?[0-9]*\\.?[0-9]+$',
|
|
586
|
+
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})$',
|
|
587
|
+
base64: '[^a-zA-Z0-9\\/\\+=]',
|
|
588
|
+
citizenId: '^\\d{12}$',
|
|
589
|
+
passport: '^[A-Z0-9]{6,12}$', // Hộ chiếu - 6-12 ký tự (chữ IN HOA và số)
|
|
590
|
+
// dnkhcn: "/^DNKHCN-[A-Z]{2}-d{4}$/",
|
|
591
|
+
// msdn: "/^d{10}$/",
|
|
592
|
+
intergerNotZero: '^[0-9]*[1-9][0-9]*$',
|
|
593
|
+
//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,})",
|
|
594
|
+
// code: "^['A-Z''0-9''._\\-']*$",
|
|
595
|
+
code: "^['A-Z''0-9''./_\\-\\/\\Đ']*$",
|
|
596
|
+
codeHsda: "^['A-Z''0-9''./_\\-']*$",
|
|
597
|
+
link_location: '(https?://)?([\\da-z.-]+)\\.([a-z.]{2,6})([/\\w .-]*)?(\\?[\\w=&,.%-]*)?',
|
|
598
|
+
link: '(https?://)?([\\da-z.-]+)\\.([a-z.]{2,6})[/\\w .-]*/?',
|
|
599
|
+
//password: "/(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[$@$!%*?&]).{8,}/",
|
|
600
|
+
accountName: '^[a-zA-Z0-9_.]{2,20}$',
|
|
601
|
+
name_or_fullName: '^[a-zA-Z0-9_ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂưăạảấầẩẫậắằẳẵặẹẻẽềềểỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễếệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵỷỹ ]{1,20}$',
|
|
602
|
+
packageName: '^(?:[a-zA-Z]+(?:d*[a-zA-Z_]*)*)(?:.[a-zA-Z]+(?:d*[a-zA-Z_]*)*)+$',
|
|
603
|
+
email: '^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$',
|
|
604
|
+
passwordRegex: '^(?!.*\\s)(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[~`!@#$%^&*()--+={}\\[\\]|\\\\:;"\'<>,.?/_₹]).{8,}$',
|
|
605
|
+
// phoneNumber: "^(\\+84|0)([235789])([0-9]{8,9})\\b",
|
|
606
|
+
phoneNumber: '^(\\+84|0)([235789])([0-9]{8,9})$',
|
|
607
|
+
seqNum: '^(100|[0-9]{1,2})$',
|
|
608
|
+
link_basemap: '(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,})?',
|
|
609
|
+
alphaDashBreakLineVN: "^[0-9a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\\.+,:%&=;s.\\/\\-_'\\(\\)\n]+$",
|
|
610
|
+
fax: '^(\\+?\\d{1,4}[\\s-]?)?(\\(?\\d{2,4}\\)?[\\s-]?)?[\\d\\s-]{5,15}$',
|
|
611
|
+
alphaDashNameVN: "^[a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\.s.\/\-\_'\\(\\)]{2,}$",
|
|
612
|
+
businessCode: '^\\d{10}(-\\d{3})?$',
|
|
613
|
+
};
|
|
614
|
+
// Các error message cho các pattern regex.
|
|
615
|
+
const PATTERN_ERROR_MESSAGES = {
|
|
616
|
+
required: '%s không được để trống!',
|
|
617
|
+
number: '%s phải là số!',
|
|
618
|
+
email: '%s không đúng định dạng địa chỉ Email!',
|
|
619
|
+
minlength: '%s có kích thước tối thiểu %s ký tự!',
|
|
620
|
+
maxlength: '%s có kích thước tối đa %s ký tự!',
|
|
621
|
+
min: '%s phải lớn hơn hoặc bằng %s!',
|
|
622
|
+
max: '%s phải nhỏ hơn hoặc bằng %s!',
|
|
623
|
+
alpha: '%s chỉ chứa ký tự thường và ký tự in hoa không dấu!',
|
|
624
|
+
alphaNumeric: '%s chỉ chứa ký tự thường, ký tự in hoa không dấu và số!',
|
|
625
|
+
name: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu, số, dấu chấm, dấu phẩy, gạch dưới _ hoặc gạch ngang -, dấu ngoặc ()!',
|
|
626
|
+
username: '%s chỉ chứa ký tự thường, số, dấu chấm và dấu gạch dưới _',
|
|
627
|
+
regexPostCode: '%s chỉ chứa ký tự thường, ký tự in hoa không dấu, số, gạch ngang -',
|
|
628
|
+
alphaDash: '%s chỉ chứa ký tự thường, ký tự in hoa không dấu, số, gạch dưới _ hoặc gạch ngang -, dấu ngoặc ()!',
|
|
629
|
+
alphaVN: '%s chỉ chứa ký tự thường và ký tự in hoa có dấu!',
|
|
630
|
+
alphaNumericVN: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu và số!',
|
|
631
|
+
alphaDashVN: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu, số, dấu chấm, dấu phẩy, gạch dưới _ hoặc gạch ngang -, dấu ngoặc ()!',
|
|
632
|
+
alphaDashNameVN: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu và ít nhất 2 ký tự!',
|
|
633
|
+
unitName: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu, số, gạch dưới _ hoặc gạch ngang -',
|
|
634
|
+
date: '%s không đúng định dạng năm tháng ngày (YYYY-MM-DD)!',
|
|
635
|
+
time: '%s không đúng định dạng giờ phút giây (HH:MM:SS)!',
|
|
636
|
+
dateTime: '%s không đúng định dạng năm tháng ngày giờ phút giây (YYYY-MM-DD HH:MM:SS)!',
|
|
637
|
+
dateVN: '%s không đúng định dạng ngày tháng năm (DD/MM/YYYY)!',
|
|
638
|
+
dateTimeVN: '%s không đúng định dạng ngày tháng năm giờ phút giây (DD/MM/YYYY HH:MI:SS)!',
|
|
639
|
+
dateShortTimeVN: '%s không đúng định dạng ngày tháng năm giờ phút (DD/MM/YYYY HH:MI)!',
|
|
640
|
+
integer: '%s phải là số nguyên!',
|
|
641
|
+
decimal: '%s phải là số thập phân!',
|
|
642
|
+
ipAddress: '%s không đúng định dạng địa chỉ IP!',
|
|
643
|
+
base64: '%s không đúng định dạng Base64!',
|
|
644
|
+
intergerNotZero: '%s phải là số nguyên dương khác 0!',
|
|
645
|
+
link_location: '%s không đúng định dạng!',
|
|
646
|
+
link: '%s không đúng định dạng!',
|
|
647
|
+
codeHsda: "%s chỉ chứa các chữ cái in hoa không dấu, số và dấu '.', '_', '-'",
|
|
648
|
+
code: "%s chỉ chứa các chữ cái in hoa không dấu, số và dấu '.', '_', '-', '/'",
|
|
649
|
+
// code: "%s chỉ chứa các chữ cái in hoa,chữ cái thường không dấu, số và dấu '.', '_', '-'",
|
|
650
|
+
accountName: '%s chỉ bao gồm các kí tự từ A-Z, các số từ 0-9 và ít nhất 2 ký tự',
|
|
651
|
+
name_or_fullName: '',
|
|
652
|
+
// pwdErrorTip:
|
|
653
|
+
// "%s phải có ít nhất 8 ký tự. Ít nhất 1 ký tự hoa, số, ký tự thường và ký tự đặc biệt",
|
|
654
|
+
phoneNumber: 'Số điện thoại không hợp lệ (Gợi ý: Số điện thoại phải bắt đầu bằng đầu số 02, 03, 05, 07, 08, 09 hoặc +84 và có độ dài 10-11 ký tự)',
|
|
655
|
+
seqNum: '(Gợi ý: Thứ tự hiển thị phải là dạng số và có giá trị từ 1-100)',
|
|
656
|
+
link_basemap: '%s không đúng định dạng!',
|
|
657
|
+
passwordRegex: '%s phải có ít nhất 8 ký tự. Ít nhất 1 ký tự hoa, ký tự thường, số và ký tự đặc biệt',
|
|
658
|
+
alphaDashBreakLineVN: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu, số, dấu chấm, dấu phẩy, gạch dưới _ hoặc gạch ngang -, dấu ngoặc ()!',
|
|
659
|
+
citizenId: '%s phải đúng định dạng 12 số!',
|
|
660
|
+
businessCode: '',
|
|
661
|
+
};
|
|
662
|
+
|
|
663
|
+
const resolvePattern = (pattern) => {
|
|
664
|
+
if (!pattern)
|
|
665
|
+
return { type: 'unknown', value: '' };
|
|
666
|
+
// Trường hợp là RegExp thực sự
|
|
667
|
+
if (pattern instanceof RegExp)
|
|
668
|
+
return { type: 'regexObject', value: pattern };
|
|
669
|
+
// Trường hợp là tên preset (ưu tiên nếu trùng)
|
|
670
|
+
if (pattern in PATTERN_PRESETS) {
|
|
671
|
+
return { type: 'regexKey', value: PATTERN_PRESETS[pattern] };
|
|
672
|
+
}
|
|
673
|
+
try {
|
|
674
|
+
// Trường hợp là chuỗi regex dạng "^abc$"
|
|
675
|
+
return { type: 'regexString', value: new RegExp(pattern) };
|
|
676
|
+
}
|
|
677
|
+
catch (err) {
|
|
678
|
+
console.warn(`Không thể parse pattern "${pattern}"`, err);
|
|
679
|
+
return { type: 'unknown', value: '' };
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
const DEFAULT_INPUT_VALUE = '';
|
|
684
|
+
/**
|
|
685
|
+
* Interface base chung cho Các dạng Input Field.
|
|
686
|
+
*/
|
|
687
|
+
class InputBaseField extends BaseField {
|
|
688
|
+
constructor(init) {
|
|
689
|
+
super(init);
|
|
690
|
+
/**
|
|
691
|
+
* Gán giá trị cho các props cần giá trị mặc định ở Input.
|
|
692
|
+
*/
|
|
693
|
+
this.controlType = ControlTypeEnum.Input;
|
|
694
|
+
this.value = DEFAULT_INPUT_VALUE;
|
|
695
|
+
this.initialValue = DEFAULT_INPUT_VALUE;
|
|
696
|
+
this.suffixes = [];
|
|
697
|
+
this.isCurrency = false;
|
|
698
|
+
Object.assign(this, init);
|
|
699
|
+
}
|
|
700
|
+
// Mảng ValidatorFn các validation chung được hỗ trợ sẵn bởi Reactive form của angular cho Input.
|
|
701
|
+
getInputCommonValidators() {
|
|
702
|
+
const validators = this.getCommonValidators();
|
|
703
|
+
if (this.minLength)
|
|
704
|
+
validators.push(Validators.minLength(this.minLength));
|
|
705
|
+
if (this.maxLength)
|
|
706
|
+
validators.push(Validators.maxLength(this.maxLength));
|
|
707
|
+
if (this.pattern) {
|
|
708
|
+
const resolvePatternResult = resolvePattern(this.pattern);
|
|
709
|
+
if (resolvePatternResult?.type !== 'unknown')
|
|
710
|
+
validators.push(Validators.pattern(resolvePatternResult.value));
|
|
711
|
+
}
|
|
712
|
+
return validators;
|
|
713
|
+
}
|
|
714
|
+
// Mảng ValidatorFn các custom validation có thể dùng cho Input.
|
|
715
|
+
getInputCustomValidators() {
|
|
716
|
+
const validators = this.getCustomValidators();
|
|
717
|
+
validators.push(noLeadingSpaceValidator());
|
|
718
|
+
return validators;
|
|
719
|
+
}
|
|
720
|
+
// Tạo Form Control cho Input Field.
|
|
721
|
+
toFormControl() {
|
|
722
|
+
const commonValidators = this.getInputCommonValidators();
|
|
723
|
+
const customValidators = this.getInputCustomValidators();
|
|
724
|
+
return new FormControl(this.value ?? '', [...commonValidators, ...customValidators]);
|
|
725
|
+
}
|
|
726
|
+
// Giá trị mặc định.
|
|
727
|
+
getDefaultValue() {
|
|
728
|
+
return DEFAULT_INPUT_VALUE;
|
|
729
|
+
}
|
|
730
|
+
toFormValue(modelValue) {
|
|
731
|
+
return String(modelValue);
|
|
732
|
+
}
|
|
733
|
+
getErrorMessage(errorKey, errorValue, allFields) {
|
|
734
|
+
if (errorKey === CommonValidaterEnum.Pattern) {
|
|
735
|
+
if (this.pattern)
|
|
736
|
+
return getDefaultPatternErrorMessage(this.label, this.pattern);
|
|
737
|
+
}
|
|
738
|
+
if (errorKey === CommonValidaterEnum.MinLength)
|
|
739
|
+
return getDefaultMinLengthErrorMessage(this.label, errorValue);
|
|
740
|
+
if (errorKey === CommonValidaterEnum.MaxLength)
|
|
741
|
+
return getDefaultMaxLengthErrorMessage(this.label, errorValue);
|
|
742
|
+
if (errorKey === CustomValidaterEnum.LeadingSpace)
|
|
743
|
+
return getLeadingSpaceErrorMessage(this.label);
|
|
744
|
+
return super.getErrorMessage(errorKey, errorValue, allFields);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Interface của Input Field type là Text.
|
|
750
|
+
*/
|
|
751
|
+
class InputTextField extends InputBaseField {
|
|
752
|
+
constructor(init) {
|
|
753
|
+
super(init);
|
|
754
|
+
/**
|
|
755
|
+
* Gán giá trị cho các props cần giá trị mặc định ở Input Text.
|
|
756
|
+
*/
|
|
757
|
+
this.type = FieldTypeEnum.InputText;
|
|
758
|
+
Object.assign(this, init);
|
|
759
|
+
}
|
|
760
|
+
// Tạo Form Control cho Input Text Field.
|
|
761
|
+
toFormControl() {
|
|
762
|
+
const commonValidators = this.getInputCommonValidators();
|
|
763
|
+
const customValidators = this.getInputCustomValidators();
|
|
764
|
+
return new FormControl(this.value ?? '', [...commonValidators, ...customValidators]);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Interface của Input Field type là Password.
|
|
770
|
+
*/
|
|
771
|
+
class InputPasswordField extends InputBaseField {
|
|
772
|
+
constructor(init) {
|
|
773
|
+
super(init);
|
|
774
|
+
/**
|
|
775
|
+
* Gán giá trị cho các props cần giá trị mặc định ở Input Password.
|
|
776
|
+
*/
|
|
777
|
+
this.type = FieldTypeEnum.InputPassword;
|
|
778
|
+
Object.assign(this, init);
|
|
779
|
+
}
|
|
780
|
+
// Mảng ValidatorFn các validation chung được hỗ trợ sẵn bởi Reactive form của angular cho Input Password.
|
|
781
|
+
getInputPasswordCommonValidators() {
|
|
782
|
+
const validators = this.getInputCommonValidators();
|
|
783
|
+
return validators;
|
|
784
|
+
}
|
|
785
|
+
// Mảng ValidatorFn các validation chung được hỗ trợ sẵn bởi angular cho Input Password.
|
|
786
|
+
getInputPasswordCustomValidators() {
|
|
787
|
+
const validators = this.getInputCustomValidators();
|
|
788
|
+
return validators;
|
|
789
|
+
}
|
|
790
|
+
// Tạo Form Control cho Input Password Field.
|
|
791
|
+
toFormControl() {
|
|
792
|
+
const commonValidators = this.getInputPasswordCommonValidators();
|
|
793
|
+
const customValidators = this.getInputPasswordCustomValidators();
|
|
794
|
+
return new FormControl(this.value ?? '', [...commonValidators, ...customValidators]);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
571
798
|
/**
|
|
572
799
|
* Interface base chung cho Các dạng Input Field.
|
|
573
800
|
*/
|
|
@@ -2641,206 +2868,86 @@ const asyncUsernameValidator = (takenUsernames) => {
|
|
|
2641
2868
|
};
|
|
2642
2869
|
};
|
|
2643
2870
|
// Không có ký tự đặc biệt.
|
|
2644
|
-
const noSpecialCharValidator = () => {
|
|
2645
|
-
return (control) => {
|
|
2646
|
-
const valid = /^[a-zA-Z0-9]*$/.test(control.value);
|
|
2647
|
-
return valid ? null : { noSpecialChar: true };
|
|
2648
|
-
};
|
|
2649
|
-
};
|
|
2650
|
-
// Username không được nằm trong blacklist.
|
|
2651
|
-
const usernameBlacklistValidator = (blacklist) => {
|
|
2652
|
-
return (control) => {
|
|
2653
|
-
return blacklist.includes(control.value) ? { blacklisted: true } : null;
|
|
2654
|
-
};
|
|
2655
|
-
};
|
|
2656
|
-
// Có thuộc mimetypes từ mảng mimetypes được chỉ định hay không?
|
|
2657
|
-
const acceptedMimeTypesValidator = (acceptedMimeTypes) => {
|
|
2658
|
-
return (control) => {
|
|
2659
|
-
const value = control?.value;
|
|
2660
|
-
if (value) {
|
|
2661
|
-
let fileType = '';
|
|
2662
|
-
if (value instanceof File) {
|
|
2663
|
-
fileType = value.type;
|
|
2664
|
-
}
|
|
2665
|
-
if (isValidJSON(value)) {
|
|
2666
|
-
const { contentType } = JSON.parse(value)[0] || {};
|
|
2667
|
-
if (contentType)
|
|
2668
|
-
fileType = contentType;
|
|
2669
|
-
}
|
|
2670
|
-
if (fileType) {
|
|
2671
|
-
if (!acceptedMimeTypes.includes(fileType)) {
|
|
2672
|
-
return {
|
|
2673
|
-
acceptedMimeTypes: {
|
|
2674
|
-
actualValue: fileType,
|
|
2675
|
-
requiredValue: `Nằm trong ${acceptedMimeTypes}`,
|
|
2676
|
-
},
|
|
2677
|
-
};
|
|
2678
|
-
}
|
|
2679
|
-
}
|
|
2680
|
-
}
|
|
2681
|
-
return null;
|
|
2682
|
-
};
|
|
2683
|
-
};
|
|
2684
|
-
const maxFileSizeInMBValidator = (maxSizeInMB) => {
|
|
2685
|
-
return (control) => {
|
|
2686
|
-
const file = control?.value;
|
|
2687
|
-
if (file) {
|
|
2688
|
-
const fileSizeInMB = formatFileSize(file.size, FileSizeTypeEnum.MB);
|
|
2689
|
-
if (fileSizeInMB > maxSizeInMB) {
|
|
2690
|
-
return {
|
|
2691
|
-
maxSizeInMB: {
|
|
2692
|
-
actualValue: fileSizeInMB,
|
|
2693
|
-
requiredValue: `Nhỏ hơn ${maxSizeInMB}`,
|
|
2694
|
-
},
|
|
2695
|
-
};
|
|
2696
|
-
}
|
|
2697
|
-
}
|
|
2698
|
-
return null;
|
|
2699
|
-
};
|
|
2700
|
-
};
|
|
2701
|
-
const reminderCustomRequiredValidator = () => {
|
|
2702
|
-
return (control) => {
|
|
2703
|
-
const reminderValue = control?.value;
|
|
2704
|
-
if (!reminderValue) {
|
|
2705
|
-
return {
|
|
2706
|
-
reminderCustomRequired: {
|
|
2707
|
-
requiredValue: `Giá trị radio và cả từ select hoặc date`,
|
|
2708
|
-
},
|
|
2709
|
-
};
|
|
2710
|
-
}
|
|
2711
|
-
if (reminderValue) {
|
|
2712
|
-
const { reminderDate } = reminderValue;
|
|
2713
|
-
if (!reminderDate) {
|
|
2714
|
-
return {
|
|
2715
|
-
reminderCustomRequired: {
|
|
2716
|
-
actualValue: reminderDate,
|
|
2717
|
-
requiredValue: `Giá trị từ select hoặc date`,
|
|
2718
|
-
},
|
|
2719
|
-
};
|
|
2720
|
-
}
|
|
2721
|
-
}
|
|
2722
|
-
return null;
|
|
2723
|
-
};
|
|
2724
|
-
};
|
|
2725
|
-
|
|
2726
|
-
// Các patterns regex thường dùng trong ứng dụng
|
|
2727
|
-
const PATTERN_PRESETS = {
|
|
2728
|
-
alpha: '^[a-zA-Z]+$',
|
|
2729
|
-
alphaNumeric: '^[a-zA-Z0-9]+$',
|
|
2730
|
-
name: "^[0-9a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\\.+,:%&=;s.\\/\\-_'\\()]+$",
|
|
2731
|
-
username: '^[a-z0-9_.s]+$',
|
|
2732
|
-
regexPostCode: '^[a-zA-Z0-9-s]+$',
|
|
2733
|
-
alphaDash: '^[a-zA-Z0-9_-s.]+$',
|
|
2734
|
-
alphaVN: '^[a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\\,s]+$',
|
|
2735
|
-
alphaNumericVN: '^[0-9a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\\s]+$',
|
|
2736
|
-
alphaDashVN: "^[0-9a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\\.+,:%&=;s.\\/\\-_'\\()]+$",
|
|
2737
|
-
unitName: '^[a-zA-Z0-9 ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵỷỹs_-]+$',
|
|
2738
|
-
date: '([12]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01]))',
|
|
2739
|
-
time: '(?=[01]\\d|2[0123])=(?=[012345]\\d)=(?=[012345]\\d)',
|
|
2740
|
-
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]',
|
|
2741
|
-
// dateV: "^(0?[1-9]|[12][0-9]|3[01])[\\/](0?[1-9]|1[012])[\\/]\\d{4}$",
|
|
2742
|
-
// dateV: /^(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-](19|20)\d\d/,
|
|
2743
|
-
// dateV: "^([0-2][0-9]|(3)[0-1])(\-)(((0)[0-9])|((1)[0-2]))(\-)\d{4}$",
|
|
2744
|
-
dateVN: '^(?=0[1-9]|[12]d|3[01])([/.-])(?=0[1-9]|1[012])\\1(?=19|20)dd$',
|
|
2745
|
-
dateTimeVN: '^(0?[1-9]|[12][0-9]|3[01])[\\/](0?[1-9]|1[012])[\\/]\\d{4} (\\d{2})=(\\d{2})=(\\d{2})$',
|
|
2746
|
-
dateShortTimeVN: '^(0?[1-9]|[12][0-9]|3[01])[\\/](0?[1-9]|1[012])[\\/]\\d{4} (\\d{2})=(\\d{2})$',
|
|
2747
|
-
integer: '^\\-?[0-9]+$',
|
|
2748
|
-
decimal: '^\\-?[0-9]*\\.?[0-9]+$',
|
|
2749
|
-
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})$',
|
|
2750
|
-
base64: '[^a-zA-Z0-9\\/\\+=]',
|
|
2751
|
-
citizenId: '^\\d{12}$',
|
|
2752
|
-
passport: '^[A-Z0-9]{6,12}$', // Hộ chiếu - 6-12 ký tự (chữ IN HOA và số)
|
|
2753
|
-
// dnkhcn: "/^DNKHCN-[A-Z]{2}-d{4}$/",
|
|
2754
|
-
// msdn: "/^d{10}$/",
|
|
2755
|
-
intergerNotZero: '^[0-9]*[1-9][0-9]*$',
|
|
2756
|
-
//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,})",
|
|
2757
|
-
// code: "^['A-Z''0-9''._\\-']*$",
|
|
2758
|
-
code: "^['A-Z''0-9''./_\\-\\/\\Đ']*$",
|
|
2759
|
-
codeHsda: "^['A-Z''0-9''./_\\-']*$",
|
|
2760
|
-
link_location: '(https?://)?([\\da-z.-]+)\\.([a-z.]{2,6})([/\\w .-]*)?(\\?[\\w=&,.%-]*)?',
|
|
2761
|
-
link: '(https?://)?([\\da-z.-]+)\\.([a-z.]{2,6})[/\\w .-]*/?',
|
|
2762
|
-
//password: "/(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[$@$!%*?&]).{8,}/",
|
|
2763
|
-
accountName: '^[a-zA-Z0-9_.]{2,20}$',
|
|
2764
|
-
name_or_fullName: '^[a-zA-Z0-9_ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂưăạảấầẩẫậắằẳẵặẹẻẽềềểỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễếệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵỷỹ ]{1,20}$',
|
|
2765
|
-
packageName: '^(?:[a-zA-Z]+(?:d*[a-zA-Z_]*)*)(?:.[a-zA-Z]+(?:d*[a-zA-Z_]*)*)+$',
|
|
2766
|
-
email: '^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$',
|
|
2767
|
-
passwordRegex: '^(?!.*\\s)(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[~`!@#$%^&*()--+={}\\[\\]|\\\\:;"\'<>,.?/_₹]).{8,}$',
|
|
2768
|
-
// phoneNumber: "^(\\+84|0)([235789])([0-9]{8,9})\\b",
|
|
2769
|
-
phoneNumber: '^(\\+84|0)([235789])([0-9]{8,9})$',
|
|
2770
|
-
seqNum: '^(100|[0-9]{1,2})$',
|
|
2771
|
-
link_basemap: '(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,})?',
|
|
2772
|
-
alphaDashBreakLineVN: "^[0-9a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\\.+,:%&=;s.\\/\\-_'\\(\\)\n]+$",
|
|
2773
|
-
fax: '^(\\+?\\d{1,4}[\\s-]?)?(\\(?\\d{2,4}\\)?[\\s-]?)?[\\d\\s-]{5,15}$',
|
|
2774
|
-
alphaDashNameVN: "^[a-zA-Z_ ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵýỷỹ\.s.\/\-\_'\\(\\)]{2,}$",
|
|
2775
|
-
businessCode: '^\\d{10}(-\\d{3})?$',
|
|
2776
|
-
};
|
|
2777
|
-
// Các error message cho các pattern regex.
|
|
2778
|
-
const PATTERN_ERROR_MESSAGES = {
|
|
2779
|
-
required: '%s không được để trống!',
|
|
2780
|
-
number: '%s phải là số!',
|
|
2781
|
-
email: '%s không đúng định dạng địa chỉ Email!',
|
|
2782
|
-
minlength: '%s có kích thước tối thiểu %s ký tự!',
|
|
2783
|
-
maxlength: '%s có kích thước tối đa %s ký tự!',
|
|
2784
|
-
min: '%s phải lớn hơn hoặc bằng %s!',
|
|
2785
|
-
max: '%s phải nhỏ hơn hoặc bằng %s!',
|
|
2786
|
-
alpha: '%s chỉ chứa ký tự thường và ký tự in hoa không dấu!',
|
|
2787
|
-
alphaNumeric: '%s chỉ chứa ký tự thường, ký tự in hoa không dấu và số!',
|
|
2788
|
-
name: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu, số, dấu chấm, dấu phẩy, gạch dưới _ hoặc gạch ngang -, dấu ngoặc ()!',
|
|
2789
|
-
username: '%s chỉ chứa ký tự thường, số, dấu chấm và dấu gạch dưới _',
|
|
2790
|
-
regexPostCode: '%s chỉ chứa ký tự thường, ký tự in hoa không dấu, số, gạch ngang -',
|
|
2791
|
-
alphaDash: '%s chỉ chứa ký tự thường, ký tự in hoa không dấu, số, gạch dưới _ hoặc gạch ngang -, dấu ngoặc ()!',
|
|
2792
|
-
alphaVN: '%s chỉ chứa ký tự thường và ký tự in hoa có dấu!',
|
|
2793
|
-
alphaNumericVN: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu và số!',
|
|
2794
|
-
alphaDashVN: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu, số, dấu chấm, dấu phẩy, gạch dưới _ hoặc gạch ngang -, dấu ngoặc ()!',
|
|
2795
|
-
alphaDashNameVN: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu và ít nhất 2 ký tự!',
|
|
2796
|
-
unitName: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu, số, gạch dưới _ hoặc gạch ngang -',
|
|
2797
|
-
date: '%s không đúng định dạng năm tháng ngày (YYYY-MM-DD)!',
|
|
2798
|
-
time: '%s không đúng định dạng giờ phút giây (HH:MM:SS)!',
|
|
2799
|
-
dateTime: '%s không đúng định dạng năm tháng ngày giờ phút giây (YYYY-MM-DD HH:MM:SS)!',
|
|
2800
|
-
dateVN: '%s không đúng định dạng ngày tháng năm (DD/MM/YYYY)!',
|
|
2801
|
-
dateTimeVN: '%s không đúng định dạng ngày tháng năm giờ phút giây (DD/MM/YYYY HH:MI:SS)!',
|
|
2802
|
-
dateShortTimeVN: '%s không đúng định dạng ngày tháng năm giờ phút (DD/MM/YYYY HH:MI)!',
|
|
2803
|
-
integer: '%s phải là số nguyên!',
|
|
2804
|
-
decimal: '%s phải là số thập phân!',
|
|
2805
|
-
ipAddress: '%s không đúng định dạng địa chỉ IP!',
|
|
2806
|
-
base64: '%s không đúng định dạng Base64!',
|
|
2807
|
-
intergerNotZero: '%s phải là số nguyên dương khác 0!',
|
|
2808
|
-
link_location: '%s không đúng định dạng!',
|
|
2809
|
-
link: '%s không đúng định dạng!',
|
|
2810
|
-
codeHsda: "%s chỉ chứa các chữ cái in hoa không dấu, số và dấu '.', '_', '-'",
|
|
2811
|
-
code: "%s chỉ chứa các chữ cái in hoa không dấu, số và dấu '.', '_', '-', '/'",
|
|
2812
|
-
// code: "%s chỉ chứa các chữ cái in hoa,chữ cái thường không dấu, số và dấu '.', '_', '-'",
|
|
2813
|
-
accountName: '%s chỉ bao gồm các kí tự từ A-Z, các số từ 0-9 và ít nhất 2 ký tự',
|
|
2814
|
-
name_or_fullName: '',
|
|
2815
|
-
// pwdErrorTip:
|
|
2816
|
-
// "%s phải có ít nhất 8 ký tự. Ít nhất 1 ký tự hoa, số, ký tự thường và ký tự đặc biệt",
|
|
2817
|
-
phoneNumber: 'Số điện thoại không hợp lệ (Gợi ý: Số điện thoại phải bắt đầu bằng đầu số 02, 03, 05, 07, 08, 09 hoặc +84 và có độ dài 10-11 ký tự)',
|
|
2818
|
-
seqNum: '(Gợi ý: Thứ tự hiển thị phải là dạng số và có giá trị từ 1-100)',
|
|
2819
|
-
link_basemap: '%s không đúng định dạng!',
|
|
2820
|
-
passwordRegex: '%s phải có ít nhất 8 ký tự. Ít nhất 1 ký tự hoa, ký tự thường, số và ký tự đặc biệt',
|
|
2821
|
-
alphaDashBreakLineVN: '%s chỉ chứa ký tự thường, ký tự in hoa có dấu, số, dấu chấm, dấu phẩy, gạch dưới _ hoặc gạch ngang -, dấu ngoặc ()!',
|
|
2822
|
-
citizenId: '%s phải đúng định dạng 12 số!',
|
|
2823
|
-
businessCode: '',
|
|
2871
|
+
const noSpecialCharValidator = () => {
|
|
2872
|
+
return (control) => {
|
|
2873
|
+
const valid = /^[a-zA-Z0-9]*$/.test(control.value);
|
|
2874
|
+
return valid ? null : { noSpecialChar: true };
|
|
2875
|
+
};
|
|
2824
2876
|
};
|
|
2825
|
-
|
|
2826
|
-
const
|
|
2827
|
-
|
|
2828
|
-
return {
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2877
|
+
// Username không được nằm trong blacklist.
|
|
2878
|
+
const usernameBlacklistValidator = (blacklist) => {
|
|
2879
|
+
return (control) => {
|
|
2880
|
+
return blacklist.includes(control.value) ? { blacklisted: true } : null;
|
|
2881
|
+
};
|
|
2882
|
+
};
|
|
2883
|
+
// Có thuộc mimetypes từ mảng mimetypes được chỉ định hay không?
|
|
2884
|
+
const acceptedMimeTypesValidator = (acceptedMimeTypes) => {
|
|
2885
|
+
return (control) => {
|
|
2886
|
+
const value = control?.value;
|
|
2887
|
+
if (value) {
|
|
2888
|
+
let fileType = '';
|
|
2889
|
+
if (value instanceof File) {
|
|
2890
|
+
fileType = value.type;
|
|
2891
|
+
}
|
|
2892
|
+
if (isValidJSON(value)) {
|
|
2893
|
+
const { contentType } = JSON.parse(value)[0] || {};
|
|
2894
|
+
if (contentType)
|
|
2895
|
+
fileType = contentType;
|
|
2896
|
+
}
|
|
2897
|
+
if (fileType) {
|
|
2898
|
+
if (!acceptedMimeTypes.includes(fileType)) {
|
|
2899
|
+
return {
|
|
2900
|
+
acceptedMimeTypes: {
|
|
2901
|
+
actualValue: fileType,
|
|
2902
|
+
requiredValue: `Nằm trong ${acceptedMimeTypes}`,
|
|
2903
|
+
},
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
return null;
|
|
2909
|
+
};
|
|
2910
|
+
};
|
|
2911
|
+
const maxFileSizeInMBValidator = (maxSizeInMB) => {
|
|
2912
|
+
return (control) => {
|
|
2913
|
+
const file = control?.value;
|
|
2914
|
+
if (file) {
|
|
2915
|
+
const fileSizeInMB = formatFileSize(file.size, FileSizeTypeEnum.MB);
|
|
2916
|
+
if (fileSizeInMB > maxSizeInMB) {
|
|
2917
|
+
return {
|
|
2918
|
+
maxSizeInMB: {
|
|
2919
|
+
actualValue: fileSizeInMB,
|
|
2920
|
+
requiredValue: `Nhỏ hơn ${maxSizeInMB}`,
|
|
2921
|
+
},
|
|
2922
|
+
};
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
return null;
|
|
2926
|
+
};
|
|
2927
|
+
};
|
|
2928
|
+
const reminderCustomRequiredValidator = () => {
|
|
2929
|
+
return (control) => {
|
|
2930
|
+
const reminderValue = control?.value;
|
|
2931
|
+
if (!reminderValue) {
|
|
2932
|
+
return {
|
|
2933
|
+
reminderCustomRequired: {
|
|
2934
|
+
requiredValue: `Giá trị radio và cả từ select hoặc date`,
|
|
2935
|
+
},
|
|
2936
|
+
};
|
|
2937
|
+
}
|
|
2938
|
+
if (reminderValue) {
|
|
2939
|
+
const { reminderDate } = reminderValue;
|
|
2940
|
+
if (!reminderDate) {
|
|
2941
|
+
return {
|
|
2942
|
+
reminderCustomRequired: {
|
|
2943
|
+
actualValue: reminderDate,
|
|
2944
|
+
requiredValue: `Giá trị từ select hoặc date`,
|
|
2945
|
+
},
|
|
2946
|
+
};
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
return null;
|
|
2950
|
+
};
|
|
2844
2951
|
};
|
|
2845
2952
|
|
|
2846
2953
|
const getDefaultPatternErrorMessage = (label, pattern) => {
|
|
@@ -2874,6 +2981,14 @@ const getLeadingSpaceErrorMessage = (label) => {
|
|
|
2874
2981
|
return `${label || 'Trường này'} không được bắt đầu bằng khoảng trắng`;
|
|
2875
2982
|
};
|
|
2876
2983
|
|
|
2984
|
+
var FormModeEnum;
|
|
2985
|
+
(function (FormModeEnum) {
|
|
2986
|
+
FormModeEnum["Add"] = "add";
|
|
2987
|
+
FormModeEnum["Edit"] = "edit";
|
|
2988
|
+
FormModeEnum["View"] = "view";
|
|
2989
|
+
FormModeEnum["Design"] = "design";
|
|
2990
|
+
})(FormModeEnum || (FormModeEnum = {}));
|
|
2991
|
+
|
|
2877
2992
|
/**
|
|
2878
2993
|
* Abstract class chung cho Field.
|
|
2879
2994
|
*/
|
|
@@ -2928,119 +3043,23 @@ class BaseField {
|
|
|
2928
3043
|
}
|
|
2929
3044
|
}
|
|
2930
3045
|
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
* Interface base chung cho Các dạng Input Field.
|
|
2934
|
-
*/
|
|
2935
|
-
class InputBaseField extends BaseField {
|
|
2936
|
-
constructor(init) {
|
|
2937
|
-
super(init);
|
|
2938
|
-
/**
|
|
2939
|
-
* Gán giá trị cho các props cần giá trị mặc định ở Input.
|
|
2940
|
-
*/
|
|
2941
|
-
this.controlType = ControlTypeEnum.Input;
|
|
2942
|
-
this.value = DEFAULT_INPUT_VALUE;
|
|
2943
|
-
this.initialValue = DEFAULT_INPUT_VALUE;
|
|
2944
|
-
this.suffixes = [];
|
|
2945
|
-
this.isCurrency = false;
|
|
2946
|
-
Object.assign(this, init);
|
|
2947
|
-
}
|
|
2948
|
-
// Mảng ValidatorFn các validation chung được hỗ trợ sẵn bởi Reactive form của angular cho Input.
|
|
2949
|
-
getInputCommonValidators() {
|
|
2950
|
-
const validators = this.getCommonValidators();
|
|
2951
|
-
if (this.minLength)
|
|
2952
|
-
validators.push(Validators.minLength(this.minLength));
|
|
2953
|
-
if (this.maxLength)
|
|
2954
|
-
validators.push(Validators.maxLength(this.maxLength));
|
|
2955
|
-
if (this.pattern) {
|
|
2956
|
-
const resolvePatternResult = resolvePattern(this.pattern);
|
|
2957
|
-
if (resolvePatternResult?.type !== 'unknown')
|
|
2958
|
-
validators.push(Validators.pattern(resolvePatternResult.value));
|
|
2959
|
-
}
|
|
2960
|
-
return validators;
|
|
2961
|
-
}
|
|
2962
|
-
// Mảng ValidatorFn các custom validation có thể dùng cho Input.
|
|
2963
|
-
getInputCustomValidators() {
|
|
2964
|
-
const validators = this.getCustomValidators();
|
|
2965
|
-
validators.push(noLeadingSpaceValidator());
|
|
2966
|
-
return validators;
|
|
2967
|
-
}
|
|
2968
|
-
// Tạo Form Control cho Input Field.
|
|
2969
|
-
toFormControl() {
|
|
2970
|
-
const commonValidators = this.getInputCommonValidators();
|
|
2971
|
-
const customValidators = this.getInputCustomValidators();
|
|
2972
|
-
return new FormControl(this.value ?? '', [...commonValidators, ...customValidators]);
|
|
2973
|
-
}
|
|
2974
|
-
// Giá trị mặc định.
|
|
2975
|
-
getDefaultValue() {
|
|
2976
|
-
return DEFAULT_INPUT_VALUE;
|
|
2977
|
-
}
|
|
2978
|
-
toFormValue(modelValue) {
|
|
2979
|
-
return String(modelValue);
|
|
2980
|
-
}
|
|
2981
|
-
getErrorMessage(errorKey, errorValue, allFields) {
|
|
2982
|
-
if (errorKey === CommonValidaterEnum.Pattern) {
|
|
2983
|
-
if (this.pattern)
|
|
2984
|
-
return getDefaultPatternErrorMessage(this.label, this.pattern);
|
|
2985
|
-
}
|
|
2986
|
-
if (errorKey === CommonValidaterEnum.MinLength)
|
|
2987
|
-
return getDefaultMinLengthErrorMessage(this.label, errorValue);
|
|
2988
|
-
if (errorKey === CommonValidaterEnum.MaxLength)
|
|
2989
|
-
return getDefaultMaxLengthErrorMessage(this.label, errorValue);
|
|
2990
|
-
if (errorKey === CustomValidaterEnum.LeadingSpace)
|
|
2991
|
-
return getLeadingSpaceErrorMessage(this.label);
|
|
2992
|
-
return super.getErrorMessage(errorKey, errorValue, allFields);
|
|
2993
|
-
}
|
|
2994
|
-
}
|
|
2995
|
-
|
|
2996
|
-
/**
|
|
2997
|
-
* Interface của Input Field type là Text.
|
|
2998
|
-
*/
|
|
2999
|
-
class InputTextField extends InputBaseField {
|
|
3046
|
+
// Dữ liệu sau khi đã tiến hành xử lý gom nhóm từ fields và groups.
|
|
3047
|
+
class GroupedFields {
|
|
3000
3048
|
constructor(init) {
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
* Gán giá trị cho các props cần giá trị mặc định ở Input Text.
|
|
3004
|
-
*/
|
|
3005
|
-
this.type = FieldTypeEnum.InputText;
|
|
3049
|
+
this.noGroup = [];
|
|
3050
|
+
this.grouped = [];
|
|
3006
3051
|
Object.assign(this, init);
|
|
3007
3052
|
}
|
|
3008
|
-
// Tạo Form Control cho Input Text Field.
|
|
3009
|
-
toFormControl() {
|
|
3010
|
-
const commonValidators = this.getInputCommonValidators();
|
|
3011
|
-
const customValidators = this.getInputCustomValidators();
|
|
3012
|
-
return new FormControl(this.value ?? '', [...commonValidators, ...customValidators]);
|
|
3013
|
-
}
|
|
3014
3053
|
}
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
* Interface của Input Field type là Password.
|
|
3018
|
-
*/
|
|
3019
|
-
class InputPasswordField extends InputBaseField {
|
|
3054
|
+
// Đại diện cho 1 group.
|
|
3055
|
+
class FieldGroup {
|
|
3020
3056
|
constructor(init) {
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
this.type = FieldTypeEnum.InputPassword;
|
|
3057
|
+
this.isActive = false;
|
|
3058
|
+
this.showArrow = true;
|
|
3059
|
+
this.disabled = false;
|
|
3060
|
+
this.required = false;
|
|
3026
3061
|
Object.assign(this, init);
|
|
3027
3062
|
}
|
|
3028
|
-
// Mảng ValidatorFn các validation chung được hỗ trợ sẵn bởi Reactive form của angular cho Input Password.
|
|
3029
|
-
getInputPasswordCommonValidators() {
|
|
3030
|
-
const validators = this.getInputCommonValidators();
|
|
3031
|
-
return validators;
|
|
3032
|
-
}
|
|
3033
|
-
// Mảng ValidatorFn các validation chung được hỗ trợ sẵn bởi angular cho Input Password.
|
|
3034
|
-
getInputPasswordCustomValidators() {
|
|
3035
|
-
const validators = this.getInputCustomValidators();
|
|
3036
|
-
return validators;
|
|
3037
|
-
}
|
|
3038
|
-
// Tạo Form Control cho Input Password Field.
|
|
3039
|
-
toFormControl() {
|
|
3040
|
-
const commonValidators = this.getInputPasswordCommonValidators();
|
|
3041
|
-
const customValidators = this.getInputPasswordCustomValidators();
|
|
3042
|
-
return new FormControl(this.value ?? '', [...commonValidators, ...customValidators]);
|
|
3043
|
-
}
|
|
3044
3063
|
}
|
|
3045
3064
|
|
|
3046
3065
|
const buildForm = (fields, mode, model) => {
|
|
@@ -3100,25 +3119,6 @@ const createSelectPlaceholder = (field) => {
|
|
|
3100
3119
|
return `Nhập ${field.key?.toLowerCase()}`;
|
|
3101
3120
|
};
|
|
3102
3121
|
|
|
3103
|
-
// Dữ liệu sau khi đã tiến hành xử lý gom nhóm từ fields và groups.
|
|
3104
|
-
class GroupedFields {
|
|
3105
|
-
constructor(init) {
|
|
3106
|
-
this.noGroup = [];
|
|
3107
|
-
this.grouped = [];
|
|
3108
|
-
Object.assign(this, init);
|
|
3109
|
-
}
|
|
3110
|
-
}
|
|
3111
|
-
// Đại diện cho 1 group.
|
|
3112
|
-
class FieldGroup {
|
|
3113
|
-
constructor(init) {
|
|
3114
|
-
this.isActive = false;
|
|
3115
|
-
this.showArrow = true;
|
|
3116
|
-
this.disabled = false;
|
|
3117
|
-
this.required = false;
|
|
3118
|
-
Object.assign(this, init);
|
|
3119
|
-
}
|
|
3120
|
-
}
|
|
3121
|
-
|
|
3122
3122
|
const isInputTextField = (field) => {
|
|
3123
3123
|
return field.controlType === ControlTypeEnum.Input && field.type === FieldTypeEnum.InputText;
|
|
3124
3124
|
};
|
|
@@ -3300,7 +3300,7 @@ class TreeSelectField extends SelectBaseField {
|
|
|
3300
3300
|
}
|
|
3301
3301
|
}
|
|
3302
3302
|
|
|
3303
|
-
|
|
3303
|
+
class DynamicFormService {
|
|
3304
3304
|
constructor() {
|
|
3305
3305
|
this.formConfigService = inject(FormConfigService);
|
|
3306
3306
|
/**
|
|
@@ -3458,8 +3458,8 @@ let DynamicFormService$1 = class DynamicFormService {
|
|
|
3458
3458
|
}
|
|
3459
3459
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3460
3460
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormService, providedIn: 'root' }); }
|
|
3461
|
-
}
|
|
3462
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormService
|
|
3461
|
+
}
|
|
3462
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormService, decorators: [{
|
|
3463
3463
|
type: Injectable,
|
|
3464
3464
|
args: [{
|
|
3465
3465
|
providedIn: 'root',
|
|
@@ -3667,7 +3667,7 @@ class BaseValueAccessor {
|
|
|
3667
3667
|
this.onChange = () => { };
|
|
3668
3668
|
this.onTouched = () => { };
|
|
3669
3669
|
this.isDisabled = false;
|
|
3670
|
-
this.dFormService = inject(DynamicFormService
|
|
3670
|
+
this.dFormService = inject(DynamicFormService);
|
|
3671
3671
|
this.formDataService = inject(FormDataService);
|
|
3672
3672
|
this.fieldService = inject(FieldService);
|
|
3673
3673
|
}
|
|
@@ -6384,13 +6384,13 @@ class DynamicFormComponent {
|
|
|
6384
6384
|
trackByField(index, field) {
|
|
6385
6385
|
return field.key || `field-${index}`;
|
|
6386
6386
|
}
|
|
6387
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormComponent, deps: [{ token: DynamicFormService
|
|
6387
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormComponent, deps: [{ token: DynamicFormService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6388
6388
|
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; track groupField.group.code) {\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$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: "ngmodule", type: NzGridModule }, { kind: "ngmodule", type: NzCollapseModule }, { kind: "component", type: i4$2.NzCollapsePanelComponent, selector: "nz-collapse-panel", inputs: ["nzActive", "nzDisabled", "nzShowArrow", "nzExtra", "nzHeader", "nzExpandedIcon"], outputs: ["nzActiveChange"], exportAs: ["nzCollapsePanel"] }, { kind: "component", type: i4$2.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"] }] }); }
|
|
6389
6389
|
}
|
|
6390
6390
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormComponent, decorators: [{
|
|
6391
6391
|
type: Component,
|
|
6392
6392
|
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; track groupField.group.code) {\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"] }]
|
|
6393
|
-
}], ctorParameters: () => [{ type: DynamicFormService
|
|
6393
|
+
}], ctorParameters: () => [{ type: DynamicFormService }], propDecorators: { formId: [{
|
|
6394
6394
|
type: Input
|
|
6395
6395
|
}], valueChangesDebounceTime: [{
|
|
6396
6396
|
type: Input
|
|
@@ -6398,18 +6398,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
6398
6398
|
type: Output
|
|
6399
6399
|
}] } });
|
|
6400
6400
|
|
|
6401
|
-
class DynamicFormService {
|
|
6402
|
-
constructor() { }
|
|
6403
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6404
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormService, providedIn: 'root' }); }
|
|
6405
|
-
}
|
|
6406
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DynamicFormService, decorators: [{
|
|
6407
|
-
type: Injectable,
|
|
6408
|
-
args: [{
|
|
6409
|
-
providedIn: 'root'
|
|
6410
|
-
}]
|
|
6411
|
-
}], ctorParameters: () => [] });
|
|
6412
|
-
|
|
6413
6401
|
var TableCellTypeEnum;
|
|
6414
6402
|
(function (TableCellTypeEnum) {
|
|
6415
6403
|
TableCellTypeEnum["ACTION"] = "action";
|
|
@@ -6455,12 +6443,12 @@ class ReminderOption {
|
|
|
6455
6443
|
* Public API Surface of dynamic-form
|
|
6456
6444
|
*/
|
|
6457
6445
|
// ==========================================
|
|
6458
|
-
//
|
|
6446
|
+
// 0. BASE FIELD MODELS (CẦN ĐƯỢC EXPORT TRƯỚC ĐỂ TRÁNH LỖI CIRCULAR DEPENDENCY CLASS EXTENDS UNDEFINED)
|
|
6459
6447
|
// ==========================================
|
|
6460
6448
|
|
|
6461
6449
|
/**
|
|
6462
6450
|
* Generated bundle index. Do not edit.
|
|
6463
6451
|
*/
|
|
6464
6452
|
|
|
6465
|
-
export { BaseDateField, BaseField, BaseUploadField, CombineDependTypeEnum, CommonValidaterEnum, ControlTypeEnum, CustomValidaterEnum, DYNAMIC_FORM_CONFIG, DateFieldTypeEnum, DateOptions, DatePickerField, DatePickerOutputValueTypeEnum, DateRangeField, DateRangeOutputValueTypeEnum, DependTypeEnum, DynamicFormComponent, DynamicFormService, FieldGroup, FieldTypeEnum, FileSizeTypeEnum, FormConfigService, FormModeEnum, GroupedFields, InputBaseField, InputFieldTypeEnum, InputPasswordField, InputTextField, MultiSelectField, RadioBaseField, ReminderOption, ReminderTypeRadioField, ReminderValue, SelectBaseField, SelectFieldTypeEnum, SelectOption, SelectOutputValueTypeEnum, SingleSelectField, TableCellTypeEnum, TextareaField, TreeSelectField, UploadFieldTypeEnum, UploadOutputValueTypeEnum, ViewModeEnum };
|
|
6453
|
+
export { BaseDateField, BaseField, BaseUploadField, CombineDependTypeEnum, CommonValidaterEnum, ControlTypeEnum, CustomValidaterEnum, DYNAMIC_FORM_CONFIG, DateFieldTypeEnum, DateOptions, DatePickerField, DatePickerOutputValueTypeEnum, DateRangeField, DateRangeOutputValueTypeEnum, DependTypeEnum, DynamicFormComponent, DynamicFormService, FieldGroup, FieldTypeEnum, FileSizeTypeEnum, FormConfigService, FormDataService, FormModeEnum, GroupedFields, InputBaseField, InputFieldTypeEnum, InputPasswordField, InputTextField, MultiSelectField, RadioBaseField, ReminderOption, ReminderTypeRadioField, ReminderValue, SelectBaseField, SelectFieldTypeEnum, SelectOption, SelectOutputValueTypeEnum, SingleSelectField, TableCellTypeEnum, TextareaField, TreeSelectField, UploadFieldTypeEnum, UploadOutputValueTypeEnum, ViewModeEnum };
|
|
6466
6454
|
//# sourceMappingURL=ldquocc-dynamic-form.mjs.map
|