@libs-ui/components-inputs-add
v0.2.356-1
Published
> Component cho phép thêm/xóa nhiều input fields động với validation và customization đầy đủ
Readme
@libs-ui/components-inputs-add
Component cho phép thêm/xóa nhiều input fields động với validation và customization đầy đủ
Version: 0.2.355-14
Giới thiệu
LibsUiComponentsInputsAddComponent là một standalone Angular component để quản lý danh sách các input fields động. Component cho phép người dùng thêm/xóa fields, validate từng field riêng biệt, và kiểm tra duplicate values.
Tính năng
- ✅ Thêm/xóa input fields động
- ✅ Validation cho từng field riêng biệt
- ✅ Kiểm tra duplicate values
- ✅ Min/Max items configuration
- ✅ Custom button configuration
- ✅ OnPush Change Detection
- ✅ Angular Signals
- ✅ Two-way binding với items array
Khi nào sử dụng
- Cần nhập nhiều giá trị cùng loại (emails, phone numbers, URLs...)
- Cho phép người dùng thêm/xóa fields động
- Cần validation cho từng field riêng biệt
- Quản lý danh sách inputs với min/max items
- Cần kiểm tra duplicate values giữa các fields
Important Notes
⚠️ fieldNameBind Required: Phải truyền fieldNameBind để xác định property name trong items array.
⚠️ items Model: items là model (two-way binding), component tự động cập nhật array khi add/remove.
⚠️ Validation Timing: Validation chạy sau 250ms debounce khi value change hoặc remove item.
⚠️ ignoreValidEmptyField: Khi true, chỉ cần ít nhất 1 field có giá trị là valid (không bắt buộc tất cả).
Cài đặt
# npm
npm install @libs-ui/components-inputs-add
# yarn
yarn add @libs-ui/components-inputs-addImport
import { LibsUiComponentsInputsAddComponent, IInputAdd, IInputAddFunctionControlEvent } from '@libs-ui/components-inputs-add';
@Component({
standalone: true,
imports: [LibsUiComponentsInputsAddComponent],
// ...
})
export class YourComponent {}Ví dụ
Basic
<libs_ui-components-inputs-add
[fieldNameBind]="'email'"
[(items)]="emailItems"
[placeholder]="'Nhập email'"
[labelConfig]="{
labelLeft: 'Email addresses',
required: true
}" />export class ExampleComponent {
emailItems = signal<Array<IInputAdd>>([{ email: '' }]);
}Min/Max Items
<libs_ui-components-inputs-add
[fieldNameBind]="'phone'"
[(items)]="phoneItems"
[minItems]="2"
[maxItems]="10"
[placeholder]="'Nhập số điện thoại'" />With Validation & Duplicate Check
<libs_ui-components-inputs-add
[fieldNameBind]="'url'"
[(items)]="urlItems"
[placeholder]="'https://example.com'"
[validRequired]="{
isRequired: true,
message: 'URL is required'
}"
[validDuplicate]="{
message: 'URL already exists'
}"
(outValueChange)="onValueChange($event)"
(outFunctionsControl)="onFunctionsControl($event)" />export class ExampleComponent {
urlItems = signal<Array<IInputAdd>>([{ url: '' }]);
functionControls = signal<IInputAddFunctionControlEvent | null>(null);
onValueChange(event: IEmitValueChange) {
console.log('Value changed:', event.value, event.item);
}
async validateAll() {
const isValid = await this.functionControls()?.checkIsValid();
console.log('Is valid:', isValid);
}
}Custom Button & Ignore Empty Field Validation
<libs_ui-components-inputs-add
[fieldNameBind]="'tag'"
[(items)]="tagItems"
[maxItems]="8"
[ignoreValidEmptyField]="true"
[addItemButtonConfig]="{
type: 'button-primary',
label: 'Add Tag',
classIconLeft: 'libs-ui-icon-add'
}"
[validRequired]="{
isRequired: true,
message: 'At least one tag is required'
}" />API
libs_ui-components-inputs-add
Inputs
| Property | Type | Default | Description |
| ---------------------------------- | -------------------------------- | ----------------------------------------- | ----------------------------------------- |
| [acceptNegativeValue] | boolean | false | Cho phép giá trị âm (với dataType number) |
| [addItemButtonConfig] | IButton | undefined | Cấu hình button "Add New" |
| [autoAddZeroLessThan10InTypeInt] | boolean | false | Tự động thêm số 0 nếu < 10 (kiểu int) |
| [autoRemoveEmoji] | boolean | false | Tự động loại bỏ emoji khỏi input |
| [backgroundNone] | boolean | false | Sử dụng background trong suốt |
| [borderError] | boolean | false | Hiển thị border màu đỏ khi có lỗi |
| [classContainerBottomInput] | string | undefined | Class CSS cho container dưới input |
| [classContainerInput] | string | undefined | Class CSS cho container bao quanh input |
| [classInclude] | string | undefined | Class CSS cho container chính |
| [classIncludeInput] | string | undefined | Class CSS cho mỗi input field |
| [classMessageErrorInclude] | string | undefined | Class CSS cho message lỗi |
| [configItemAddToItems] | IInputAdd | undefined | Template config khi add item mới |
| [configUnitLeft] | IInputValidUnitConfig | { fieldKey: "id", fieldLabel: "label" } | Cấu hình hiển thị unit bên trái |
| [configUnitRight] | IInputValidUnitConfig | { fieldKey: "id", fieldLabel: "label" } | Cấu hình hiển thị unit bên phải |
| [dataType] | TYPE_DATA_TYPE_INPUT | undefined | Loại dữ liệu: text, number, email... |
| [defaultHeight] | number | undefined | Chiều cao mặc định |
| [disable] | boolean | false | Disable tất cả inputs |
| [emitEmptyInDataTypeNumber] | boolean | false | Emit giá trị rỗng khi dataType là number |
| [fieldNameBind] | string | required | Tên property trong items array |
| [fixedFloat] | number | undefined | Số lượng số lẻ sau dấu phẩy |
| [focusTimeOut] | number | undefined | Thời gian delay focus |
| [formInputSpacing] | number | 8 | Khoảng cách giữa các input (px) |
| [functionValid] | TYPE_FUNCTION_INPUT_VALID | undefined | Hàm validate tùy chỉnh |
| [ignoreAddItem] | boolean | false | Ẩn button "Add New" |
| [ignoreRemove] | boolean | false | Ẩn button remove |
| [ignoreShowError] | boolean | false | Ẩn hiển thị lỗi |
| [ignoreStopPropagationEvent] | boolean | false | Không chặn sự kiện lan truyền |
| [ignoreUnitRightClassReadOnly] | boolean | false | Bỏ class readonly cho unit phải |
| [ignoreValidEmptyField] | boolean | false | Chỉ cần ít nhất 1 field có giá trị |
| [ignoreWidthInput100] | boolean | false | Bỏ width 100% cho input |
| [isBaselineStyle] | boolean | false | Căn chỉnh baseline items |
| [items] | Array<IInputAdd> | required | Array items (model binding) |
| [keepPlaceholderOnly] | boolean | false | Chỉ giữ placeholder |
| [keySelectedUnitLeft] | any | undefined | Key unit trái đang chọn |
| [keySelectedUnitRight] | any | undefined | Key unit phải đang chọn |
| [labelConfig] | ILabel | undefined | Cấu hình label cho component |
| [leftTemplateItems] | ITemplateRightLeftItem | undefined | Template item bên trái |
| [maxItems] | number | 5 | Số lượng items tối đa |
| [maxLength] | number | undefined | Độ dài tối đa cho input |
| [maxLengthNumberCount] | number | undefined | Max length cho number count |
| [maxValueNumber] | number | undefined | Giá trị số tối đa |
| [minItems] | number | 1 | Số lượng items tối thiểu |
| [minValueNumber] | number | undefined | Giá trị số tối thiểu |
| [noBorder] | boolean | false | Không hiển thị border |
| [onlyAcceptNegativeValue] | boolean | false | Chỉ chấp nhận số âm |
| [paddingRightCustomSpecific] | number | undefined | Custom padding phải |
| [placeholder] | string | undefined | Placeholder cho inputs |
| [positionMessageErrorStartInput] | boolean | false | Hiển thị lỗi bắt đầu từ input |
| [readonly] | boolean | false | Readonly tất cả inputs |
| [resetAutoCompletePassword] | boolean | false | Reset autocomplete password |
| [resize] | 'auto' \| 'none' | undefined | Khả năng resize |
| [rightTemplateItems] | ITemplateRightLeftItem | undefined | Template item bên phải |
| [showCount] | boolean | false | Hiển thị đếm ký tự |
| [tagInput] | TYPE_TAG_INPUT | undefined | Tag input (textarea, input...) |
| [templateLeftBottomInput] | TemplateRef<TYPE_TEMPLATE_REF> | undefined | Template dưới trái input |
| [templateLeftOutlet] | TemplateRef<TYPE_TEMPLATE_REF> | undefined | Template outlet bên trái |
| [templateRightBottomInput] | TemplateRef<TYPE_TEMPLATE_REF> | undefined | Template dưới phải input |
| [templateRightOutlet] | TemplateRef<TYPE_TEMPLATE_REF> | undefined | Template outlet bên phải |
| [typeInput] | TYPE_INPUT | undefined | Loại input (text, password...) |
| [unitsLeft] | Array<any> | undefined | Danh sách units bên trái |
| [unitsRight] | Array<any> | undefined | Danh sách units bên phải |
| [useColorModeExist] | boolean | false | Sử dụng color mode có sẵn |
| [validDuplicate] | IMessageTranslate | undefined | Message khi có giá trị duplicate |
| [validMaxValue] | IMessageTranslate | undefined | Validate giá trị tối đa |
| [validMaxLength] | IMessageTranslate | undefined | Validate độ dài tối đa |
| [validMinLength] | IValidLength | undefined | Validate độ dài tối thiểu |
| [validMinValue] | IMessageTranslate | undefined | Validate giá trị tối thiểu |
| [validPattern] | Array<IValidPattern> | undefined | Validate theo pattern regex |
| [validRequired] | IValidRequired | undefined | Validation required |
| [valuePatternShowError] | boolean | false | Hiển thị lỗi pattern |
| [valueUpDownNumber] | number | undefined | Bước nhảy tăng giảm số |
Outputs
| Property | Type | Description |
| ----------------------- | ------------------------------- | -------------------------------- |
| (outAddItem) | IInputAdd | Emit khi thêm item mới |
| (outClickButtonLabel) | IButton | Emit khi click button trên label |
| (outFunctionsControl) | IInputAddFunctionControlEvent | Emit function controls |
| (outLabelLeftClick) | MouseEvent | Emit khi click label trái |
| (outLabelRightClick) | boolean | Emit khi click label phải |
| (outRemove) | IInputAdd | Emit khi xóa item |
| (outSwitchEventLabel) | ISwitchEvent | Emit sự kiện switch trên label |
| (outValueChange) | IEmitValueChange | Emit khi giá trị thay đổi |
FunctionsControl Methods
| Method | Description |
| -------------------------- | --------------------------------------------------------- |
| checkIsValid() | Kiểm tra validation tất cả items, trả về Promise |
| setMessageError(message) | Set error message cho tất cả items |
Types & Interfaces
interface IInputAdd extends Record<string, any> {
uniqKey?: string;
disable?: boolean;
readonly?: boolean;
ignoreRemove?: boolean;
labelConfig?: ILabel;
placeholder?: string;
maxValueNumber?: number;
minValueNumber?: number;
maxLength?: number;
unitsLeft?: Array<any>;
configUnitLeft?: IInputValidUnitConfig;
keySelectedUnitLeft?: any;
unitsRight?: Array<any>;
configUnitRight?: IInputValidUnitConfig;
keySelectedUnitRight?: any;
templateLeftOutlet?: TemplateRef<TYPE_TEMPLATE_REF>;
templateRightOutlet?: TemplateRef<TYPE_TEMPLATE_REF>;
functionControl?: IInputValidFunctionControlEvent;
[key: string]: any;
}
interface IInputAddFunctionControlEvent {
checkIsValid: () => Promise<boolean>;
setMessageError: (message: string) => Promise<void>;
}
interface IEmitValueChange {
value: string | number;
item: IInputAdd;
}Công nghệ
| Technology | Version | Purpose | | --------------- | ------- | ---------------- | | Angular | 18+ | Framework | | Angular Signals | - | State management | | TailwindCSS | 3.x | Styling | | OnPush | - | Change Detection |
Demo
npx nx serve core-uiTruy cập: http://localhost:4500/inputs/add
Unit Tests
# Chạy tests
npx nx test components-inputs-add
# Coverage
npx nx test components-inputs-add --coverage
# Watch mode
npx nx test components-inputs-add --watchLicense
MIT
