@libs-ui/components-checkbox-group
v0.2.357-4
Published
> Standalone Angular component quản lý nhóm các checkbox với two-way binding, validation bắt buộc chọn, layout linh hoạt và API điều khiển từ bên ngoài.
Readme
@libs-ui/components-checkbox-group
Standalone Angular component quản lý nhóm các checkbox với two-way binding, validation bắt buộc chọn, layout linh hoạt và API điều khiển từ bên ngoài.
Giới thiệu
LibsUiComponentsCheckboxGroupComponent là component độc lập cho phép hiển thị và quản lý một tập hợp các checkbox trong cùng một nhóm. Nó kế thừa đầy đủ khả năng của CheckboxSingleComponent cho mỗi item và bổ sung tính năng quản lý tập trung: theo dõi trạng thái chọn toàn nhóm, validation bắt buộc chọn, set trạng thái nhanh theo danh sách keys, và cấp phát API điều khiển cho component cha thông qua outFunctionsControl.
Tính năng
- ✅ Two-way binding danh sách items qua
model()— tự động đồng bộ khi trạng thái checkbox thay đổi - ✅ Set trạng thái checked/disabled hàng loạt bằng danh sách keys (
keysChecked,keysDisable) - ✅ Layout dọc (mặc định) hoặc ngang (
horizontal) với tùy chỉnh CSS linh hoạt - ✅ Validation bắt buộc chọn tích hợp (
validRequired) với thông báo lỗi i18n - ✅ API điều khiển từ bên ngoài:
checkIsValid(),reset(),resetError() - ✅ Hỗ trợ nội dung bổ sung cho từng item:
subText,subTemplate - ✅ Hiển thị nhãn tổng quát (
labelConfig) tích hợp component Label - ✅ Hỗ trợ viền bao quanh (
modeBorder) và tùy chỉnh class CSS đầy đủ
Khi nào sử dụng
- Quản lý danh sách lựa chọn nhiều giá trị (multi-select) trong form
- Cần ràng buộc người dùng phải chọn ít nhất một giá trị trước khi submit
- Cần hiển thị các checkbox theo hàng ngang để tiết kiệm diện tích màn hình
- Cần điều khiển trạng thái toàn nhóm từ bên ngoài (reset, validate) thông qua API
- Cần set sẵn trạng thái checked hoặc disabled cho một số items dựa vào dữ liệu từ API
Cài đặt
npm install @libs-ui/components-checkbox-groupImport
import {
LibsUiComponentsCheckboxGroupComponent,
ICheckboxGroupItem,
ICheckboxGroupValidRequired,
ICheckboxGroupFunctionControlEvent,
ICheckboxItem,
} from '@libs-ui/components-checkbox-group';Ví dụ sử dụng
1. Cơ bản — danh sách dọc với nhãn
import { Component, signal } from '@angular/core';
import {
LibsUiComponentsCheckboxGroupComponent,
ICheckboxGroupItem,
} from '@libs-ui/components-checkbox-group';
import { ICheckboxEvent } from '@libs-ui/components-checkbox-single';
@Component({
selector: 'app-skills-form',
standalone: true,
imports: [LibsUiComponentsCheckboxGroupComponent],
template: `
<libs_ui-components-checkbox-group
[(groups)]="skillOptions"
[labelConfig]="{ labelLeft: 'Kỹ năng', required: true }"
(outChange)="handlerSkillChange($event)"
/>
`,
})
export class SkillsFormComponent {
skillOptions = signal<ICheckboxGroupItem[]>([
{ item: { key: 'angular', label: 'Angular' } },
{ item: { key: 'react', label: 'React', checked: true } },
{ item: { key: 'vue', label: 'Vue.js' } },
{ item: { key: 'nodejs', label: 'Node.js' } },
]);
handlerSkillChange(event: ICheckboxEvent): void {
event.stopPropagation();
console.log('Checked items:', event.allCheckboxChecked);
}
}2. Layout ngang — chọn thứ trong tuần
import { Component, signal } from '@angular/core';
import {
LibsUiComponentsCheckboxGroupComponent,
ICheckboxGroupItem,
} from '@libs-ui/components-checkbox-group';
@Component({
selector: 'app-schedule-form',
standalone: true,
imports: [LibsUiComponentsCheckboxGroupComponent],
template: `
<libs_ui-components-checkbox-group
[(groups)]="weekDays"
[horizontal]="true"
[labelConfig]="{ labelLeft: 'Lịch làm việc' }"
[classItemWhenModeHorizontal]="'mr-[32px]'"
/>
`,
})
export class ScheduleFormComponent {
weekDays = signal<ICheckboxGroupItem[]>([
{ item: { key: 'mon', label: 'Thứ 2' } },
{ item: { key: 'tue', label: 'Thứ 3', checked: true } },
{ item: { key: 'wed', label: 'Thứ 4', checked: true } },
{ item: { key: 'thu', label: 'Thứ 5' } },
{ item: { key: 'fri', label: 'Thứ 6', checked: true } },
]);
}3. Validation bắt buộc chọn
import { Component, signal } from '@angular/core';
import {
LibsUiComponentsCheckboxGroupComponent,
ICheckboxGroupItem,
} from '@libs-ui/components-checkbox-group';
@Component({
selector: 'app-required-form',
standalone: true,
imports: [LibsUiComponentsCheckboxGroupComponent],
template: `
<libs_ui-components-checkbox-group
[(groups)]="categories"
[labelConfig]="{ labelLeft: 'Danh mục quan tâm', required: true }"
[validRequired]="{
message: 'Vui lòng chọn ít nhất một danh mục',
hasBorderErrorCheckbox: true
}"
[showValidateBottom]="true"
/>
`,
})
export class RequiredFormComponent {
categories = signal<ICheckboxGroupItem[]>([
{ item: { key: 'tech', label: 'Công nghệ' } },
{ item: { key: 'finance', label: 'Tài chính' } },
{ item: { key: 'health', label: 'Sức khỏe' } },
]);
}4. Điều khiển từ bên ngoài qua API
import { Component, signal } from '@angular/core';
import {
LibsUiComponentsCheckboxGroupComponent,
ICheckboxGroupItem,
ICheckboxGroupFunctionControlEvent,
} from '@libs-ui/components-checkbox-group';
@Component({
selector: 'app-form-with-api',
standalone: true,
imports: [LibsUiComponentsCheckboxGroupComponent],
template: `
<div class="flex gap-2 mb-4">
<button (click)="handlerReset()">Reset</button>
<button (click)="handlerValidate()">Validate</button>
</div>
<libs_ui-components-checkbox-group
[(groups)]="items"
[validRequired]="{ message: 'Bạn chưa chọn mục nào' }"
[showValidateBottom]="true"
(outFunctionsControl)="handlerFunctionsControl($event)"
/>
`,
})
export class FormWithApiComponent {
items = signal<ICheckboxGroupItem[]>([
{ item: { key: 'item1', label: 'Mục 1' } },
{ item: { key: 'item2', label: 'Mục 2' } },
{ item: { key: 'item3', label: 'Mục 3' } },
]);
private checkboxControl: ICheckboxGroupFunctionControlEvent | null = null;
handlerFunctionsControl(event: ICheckboxGroupFunctionControlEvent): void {
event.stopPropagation();
this.checkboxControl = event;
}
handlerReset(): void {
this.checkboxControl?.reset();
}
handlerValidate(): void {
this.checkboxControl?.checkIsValid();
}
}5. Set checked/disabled theo keys từ API
import { Component, signal } from '@angular/core';
import {
LibsUiComponentsCheckboxGroupComponent,
ICheckboxGroupItem,
} from '@libs-ui/components-checkbox-group';
@Component({
selector: 'app-keys-control',
standalone: true,
imports: [LibsUiComponentsCheckboxGroupComponent],
template: `
<libs_ui-components-checkbox-group
[(groups)]="permissions"
[fieldKey]="'id'"
[keysChecked]="checkedKeys()"
[keysDisable]="disabledKeys()"
[labelConfig]="{ labelLeft: 'Quyền truy cập' }"
/>
`,
})
export class KeysControlComponent {
permissions = signal<ICheckboxGroupItem[]>([
{ item: { id: 'read', label: 'Xem' } },
{ item: { id: 'write', label: 'Chỉnh sửa' } },
{ item: { id: 'delete', label: 'Xóa' } },
{ item: { id: 'admin', label: 'Quản trị' } },
]);
// Keys sẽ được check sẵn khi component khởi tạo hoặc khi giá trị thay đổi
checkedKeys = signal<string[]>(['read', 'write']);
// Keys sẽ bị vô hiệu hóa
disabledKeys = signal<string[]>(['admin']);
}6. Item với nội dung bổ sung (subText / subTemplate)
import { Component, signal } from '@angular/core';
import {
LibsUiComponentsCheckboxGroupComponent,
ICheckboxGroupItem,
} from '@libs-ui/components-checkbox-group';
@Component({
selector: 'app-subtext-example',
standalone: true,
imports: [LibsUiComponentsCheckboxGroupComponent],
template: `
<libs_ui-components-checkbox-group
[(groups)]="planOptions"
[labelConfig]="{ labelLeft: 'Chọn gói dịch vụ' }"
/>
`,
})
export class SubtextExampleComponent {
planOptions = signal<ICheckboxGroupItem[]>([
{
item: { key: 'basic', label: 'Gói Cơ bản' },
subText: 'Bao gồm 5GB lưu trữ và hỗ trợ email.',
classIncludeSubText: 'text-gray-500 pl-[24px] mt-[4px]',
},
{
item: { key: 'pro', label: 'Gói Pro', checked: true },
subText: 'Bao gồm 50GB lưu trữ, hỗ trợ 24/7 và API access.',
classIncludeSubText: 'text-gray-500 pl-[24px] mt-[4px]',
},
]);
}@Input()
| Input | Type | Default | Mô tả | Ví dụ |
|---|---|---|---|---|
| [(groups)] | ICheckboxGroupItem[] | bắt buộc | Danh sách items trong nhóm, hỗ trợ two-way binding để đồng bộ trạng thái checked | [(groups)]="skillOptions" |
| [classGroupWhenModeHorizontal] | string | 'flex' | Class CSS cho wrapper nhóm khi ở chế độ nằm ngang | [classGroupWhenModeHorizontal]="'flex flex-wrap'" |
| [classInclude] | string | undefined | Class CSS bổ sung cho container checkbox của mỗi item | [classInclude]="'border rounded'" |
| [classItemWhenModeHorizontal] | string | 'mr-[24px]' | Class CSS cho mỗi item khi ở chế độ nằm ngang | [classItemWhenModeHorizontal]="'mr-[32px]'" |
| [classLabelInclude] | string | undefined | Class CSS bổ sung cho nhãn của mỗi checkbox | [classLabelInclude]="'libs-ui-font-h5m'" |
| [clickExactly] | boolean | true | Nếu true, chỉ click vào ô checkbox/nhãn mới đổi trạng thái; nếu false, click vào vùng bao quanh cũng trigger | [clickExactly]="false" |
| [disable] | boolean | false | Vô hiệu hóa tương tác cho toàn bộ nhóm checkbox | [disable]="isFormLocked()" |
| [fieldKey] | string | 'key' | Tên trường dùng làm khóa định danh trong object item (dùng khi item data có field tên khác key) | [fieldKey]="'id'" |
| [horizontal] | boolean | false | Nếu true, hiển thị các item theo hàng ngang thay vì hàng dọc | [horizontal]="true" |
| [keysChecked] | string[] | undefined | Danh sách giá trị của fieldKey cần được set trạng thái checked khi khởi tạo hoặc khi thay đổi | [keysChecked]="selectedIds()" |
| [keysDisable] | string[] | undefined | Danh sách giá trị của fieldKey cần được vô hiệu hóa | [keysDisable]="lockedIds()" |
| [labelConfig] | ILabel | undefined | Cấu hình cho component Label hiển thị phía trên nhóm (nhãn, required, mô tả, nút...) | [labelConfig]="{ labelLeft: 'Kỹ năng', required: true }" |
| [modeBorder] | boolean | undefined | Hiển thị viền bao quanh từng checkbox item | [modeBorder]="true" |
| [showValidateBottom] | boolean | undefined | Nếu true, hiển thị thông báo lỗi validation ở phía dưới nhóm; nếu false (mặc định), hiển thị ở phía trên | [showValidateBottom]="true" |
| [validRequired] | ICheckboxGroupValidRequired | undefined | Cấu hình validation bắt buộc chọn ít nhất một item. Khi set, component sẽ tự validate khi checkbox thay đổi | [validRequired]="{ message: 'Vui lòng chọn ít nhất một mục' }" |
@Output()
| Output | Type | Mô tả | Handler TS | Binding HTML |
|---|---|---|---|---|
| (outChange) | ICheckboxEvent | Phát ra khi bất kỳ checkbox nào trong nhóm thay đổi trạng thái. event.allCheckboxChecked chứa danh sách tất cả items đang được chọn | handlerChange(event: ICheckboxEvent): void { event.stopPropagation(); const selected = event.allCheckboxChecked; } | (outChange)="handlerChange($event)" |
| (outFunctionsControl) | ICheckboxGroupFunctionControlEvent | Phát ra object chứa các hàm điều khiển component. Được emit một lần trong ngOnInit. Lưu lại để gọi checkIsValid(), reset(), resetError() từ bên ngoài | handlerFunctionsControl(event: ICheckboxGroupFunctionControlEvent): void { event.stopPropagation(); this.checkboxControl = event; } | (outFunctionsControl)="handlerFunctionsControl($event)" |
Types & Interfaces
import {
ICheckboxGroupItem,
ICheckboxGroupValidRequired,
ICheckboxGroupFunctionControlEvent,
ICheckboxItem,
} from '@libs-ui/components-checkbox-group';ICheckboxGroupItem
Cấu hình cho mỗi phần tử trong nhóm checkbox.
interface ICheckboxGroupItem {
/** Cấu hình chi tiết của checkbox item */
item: ICheckboxItem;
/** Văn bản bổ sung hiển thị bên dưới item khi item đang được chọn */
subText?: string;
/** Class CSS bổ sung cho phần subText */
classIncludeSubText?: string;
/** Template tùy chỉnh hiển thị khi item được chọn */
subTemplate?: TemplateRef<any>;
/** Trạng thái vô hiệu hóa tự động khi key nằm trong keysDisable (tự set bởi component) */
disableByKeys?: boolean;
}ICheckboxItem
Cấu hình chi tiết cho một checkbox đơn lẻ bên trong nhóm.
interface ICheckboxItem {
/** Khóa định danh duy nhất (dùng với fieldKey='key' mặc định) */
key?: string;
/** Trạng thái chọn của checkbox */
checked?: boolean;
/** Nhãn văn bản hiển thị cạnh checkbox */
label?: string;
/** Class CSS bổ sung cho nhãn */
classLabelInclude?: string;
/** Trạng thái vô hiệu hóa của checkbox */
disable?: boolean;
/** Vô hiệu hóa tương tác click trên nhãn nhưng vẫn cho click ô checkbox */
disableLabel?: boolean;
/** Class CSS bổ sung cho wrapper của item */
classIncludeWrapper?: string;
/** Class CSS bổ sung cho ô checkbox */
classInclude?: string;
/** Nếu true, chỉ click vào checkbox/label mới trigger (override giá trị clickExactly của group) */
clickExactly?: boolean;
/** Cấu hình popover khi di chuột vào nhãn */
popover?: IPopover;
/** Loại nội dung popover ('text' | 'component') */
typeLabelPopover?: TYPE_POPOVER_TYPE;
/** Ẩn popover khi di chuột vào nhãn */
ignoreShowPopoverLabel?: boolean;
/** Cấu hình Avatar hiển thị cạnh checkbox */
avatarConfig?: IAvatarConfig;
/** URL hình ảnh hiển thị cạnh checkbox */
linkImage?: string;
/** URL hình ảnh dự phòng khi load lỗi */
linkImageError?: string;
/** Class CSS bổ sung cho phần hình ảnh */
classImageInclude?: string;
/** Cấu hình bullet (chấm tròn màu) */
bullet?: ICheckboxBullet;
/** Mô tả chi tiết hiển thị dưới nhãn */
description?: ICheckboxItemDescription;
/** Callback xử lý sự kiện từ popover */
outEventPopover?: (event: TYPE_POPOVER_EVENT) => void;
/** Các thuộc tính mở rộng — dùng khi fieldKey trỏ đến field khác 'key' */
[key: string]: any;
}ICheckboxGroupValidRequired
Cấu hình cho tính năng validation bắt buộc chọn.
interface ICheckboxGroupValidRequired {
/** Thông báo lỗi khi không có item nào được chọn. Hỗ trợ i18n key. */
message?: string;
/** Nếu true, hiển thị viền đỏ trên các ô checkbox khi có lỗi validation */
hasBorderErrorCheckbox?: boolean;
/** Tham số nội suy cho thông báo lỗi i18n (dùng với TranslateModule) */
interpolateParams?: any;
}ICheckboxGroupFunctionControlEvent
API điều khiển component từ bên ngoài, nhận được qua (outFunctionsControl).
interface ICheckboxGroupFunctionControlEvent {
/** Kích hoạt validation, trả về true nếu có ít nhất một item được chọn */
checkIsValid: () => Promise<boolean>;
/** Xóa trạng thái hiển thị lỗi validation */
resetError: () => Promise<void>;
/** Reset toàn bộ nhóm về trạng thái chưa chọn và xóa lỗi */
reset: () => Promise<void>;
}Lưu ý quan trọng
⚠️ groups là model bắt buộc: Input [(groups)] là model.required() — component sẽ báo lỗi runtime nếu không truyền vào. Luôn khởi tạo với mảng hợp lệ (có thể rỗng []).
⚠️ subText và subTemplate chỉ hiển thị khi item được chọn: Nội dung bổ sung (subText, subTemplate) chỉ render khi group.item.checked === true. Đây là behavior có chủ đích để hiển thị thông tin chi tiết khi người dùng chọn một option.
⚠️ outFunctionsControl emit một lần duy nhất trong ngOnInit: Lưu giá trị nhận được từ output này vào biến class để sử dụng sau. Không cần subscribe lại.
⚠️ keysChecked và keysDisable phản ứng reactively: Khi thay đổi giá trị của keysChecked() hoặc keysDisable(), component tự động cập nhật trạng thái checked/disabled của các items tương ứng. Sử dụng signal cho hai input này để tận dụng tính năng này.
⚠️ fieldKey phải khớp với tên trường trong item: Khi dùng fieldKey khác 'key' (ví dụ 'id'), object trong ICheckboxItem phải có trường đó (ví dụ item.id). Vì ICheckboxItem có [key: string]: any, bạn có thể thêm bất kỳ trường nào.
⚠️ disable cấp group override disable cấp item: Khi [disable]="true" trên group, toàn bộ nhóm bị khóa kể cả khi item có disable: false. keysDisable hoạt động độc lập và không bị override bởi disable của group.
Demo
npx nx serve core-uiTruy cập: http://localhost:4500/components/checkbox/group
File demo: apps/core-ui/src/app/components/checkbox/group/group.component.ts
