@libs-ui/components-checkbox-single
v0.2.357-2
Published
> Component checkbox đơn lẻ với hỗ trợ nhãn, hình ảnh, avatar, popover, bullet và mô tả chi tiết cho Angular.
Readme
@libs-ui/components-checkbox-single
Component checkbox đơn lẻ với hỗ trợ nhãn, hình ảnh, avatar, popover, bullet và mô tả chi tiết cho Angular.
Giới thiệu
LibsUiComponentsCheckboxSingleComponent là một Standalone Angular component cung cấp giải pháp checkbox linh hoạt, vượt xa ô chọn thông thường. Component hỗ trợ hiển thị nhãn văn bản (có thể dịch i18n), tích hợp Popover khi di chuột, hiển thị hình ảnh hoặc Avatar cạnh ô chọn, bullet màu sắc để phân loại, và khu vực mô tả chi tiết bên dưới nhãn. Được xây dựng trên Angular Signals với ChangeDetectionStrategy.OnPush, đảm bảo hiệu năng tối ưu trong mọi tình huống sử dụng.
Tính năng
- ✅ Two-way binding trạng thái
checkedqua Angularmodel() - ✅ Hiển thị nhãn văn bản hỗ trợ i18n (TranslateModule)
- ✅ Tích hợp Popover (tooltip) khi di chuột vào nhãn
- ✅ Hiển thị hình ảnh hoặc Avatar cạnh ô checkbox
- ✅ Hỗ trợ icon class cạnh checkbox
- ✅ Bullet (chấm tròn màu) để phân loại trực quan
- ✅ Description (mô tả chi tiết HTML) dưới nhãn
- ✅ Chế độ
modeBorderhiển thị viền bao quanh toàn component - ✅ Trạng thái
disable,disableLabel,error,showBorderError - ✅ Trạng thái
stillOtherOptions(indeterminate) cho checkbox nhóm - ✅
ignoreCheckboxđể ẩn ô chọn, chỉ hiển thị nhãn/ảnh - ✅ Component Outlet tùy chỉnh nội dung qua
ngComponentOutlet - ✅ Hàm
revert()trong sự kiệnoutChangeđể hoàn tác khi cần (ví dụ: API thất bại) - ✅ Keyboard accessibility (Enter/Space)
Khi nào sử dụng
- Cần một ô chọn (checkbox) đơn lẻ với nhãn văn bản rõ ràng
- Cần hiển thị thông tin bổ sung cạnh checkbox (ảnh đại diện, logo, icon phân loại)
- Cần giải thích chi tiết qua popover khi người dùng di chuột vào nhãn
- Dùng trong form cài đặt, lựa chọn cấu hình phức tạp nhiều trường
- Muốn hiển thị danh sách lựa chọn dạng checkbox có kèm hình ảnh minh họa
- Cần đánh dấu màu sắc phân loại (bullet) bên cạnh mỗi lựa chọn
Cài đặt
npm install @libs-ui/components-checkbox-singleImport
import { LibsUiComponentsCheckboxSingleComponent } from '@libs-ui/components-checkbox-single';
// Interfaces & Types
import {
ICheckboxEvent,
ICheckboxBullet,
ICheckboxItemDescription,
ICheckboxChecked,
} from '@libs-ui/components-checkbox-single';Ví dụ sử dụng
1. Cơ bản — Checkbox với nhãn và two-way binding
import { Component, signal } from '@angular/core';
import { LibsUiComponentsCheckboxSingleComponent, ICheckboxEvent } from '@libs-ui/components-checkbox-single';
@Component({
selector: 'app-basic-example',
standalone: true,
imports: [LibsUiComponentsCheckboxSingleComponent],
template: `
<libs_ui-components-checkbox-single
key="accept-terms"
[(checked)]="isAccepted"
label="Tôi đồng ý với điều khoản sử dụng"
(outChange)="handlerChange($event)"
/>
<p>Trạng thái: {{ isAccepted() ? 'Đã đồng ý' : 'Chưa đồng ý' }}</p>
`,
})
export class BasicExampleComponent {
isAccepted = signal(false);
handlerChange(event: ICheckboxEvent): void {
event; // stopPropagation đã được xử lý bên trong component
console.log('key:', event.key, 'checked:', event.checked);
// Nếu cần hoàn tác (ví dụ: gọi API thất bại)
// event.revert();
}
}2. Checkbox với hình ảnh và Avatar
import { Component, signal } from '@angular/core';
import { LibsUiComponentsCheckboxSingleComponent, ICheckboxEvent } from '@libs-ui/components-checkbox-single';
import { IAvatarConfig } from '@libs-ui/components-avatar';
@Component({
selector: 'app-image-example',
standalone: true,
imports: [LibsUiComponentsCheckboxSingleComponent],
template: `
<!-- Checkbox với hình ảnh -->
<libs_ui-components-checkbox-single
key="item-with-image"
[(checked)]="imageChecked"
label="Sản phẩm A"
linkImage="https://example.com/product-a.png"
linkImageError="https://example.com/placeholder.png"
classImageInclude="w-[32px] h-[32px] rounded-[4px]"
(outChange)="handlerChange($event)"
/>
<!-- Checkbox với Avatar -->
<libs_ui-components-checkbox-single
key="user-avatar"
[(checked)]="avatarChecked"
label="Nguyễn Văn An"
[avatarConfig]="userAvatarConfig"
(outChange)="handlerChange($event)"
/>
`,
})
export class ImageExampleComponent {
imageChecked = signal(false);
avatarChecked = signal(true);
readonly userAvatarConfig: IAvatarConfig = {
linkAvatar: 'https://i.pravatar.cc/150?u=nguyen-van-an',
linkAvatarError: 'https://i.pravatar.cc/150?u=fallback',
size: 32,
textAvatar: 'Nguyễn Văn An',
idGenColor: 'nguyen-van-an',
};
handlerChange(event: ICheckboxEvent): void {
event;
console.log('checked:', event.checked);
}
}3. Checkbox với Popover và Description
import { Component, signal } from '@angular/core';
import { LibsUiComponentsCheckboxSingleComponent, ICheckboxEvent, ICheckboxItemDescription } from '@libs-ui/components-checkbox-single';
import { IPopover } from '@libs-ui/components-popover';
@Component({
selector: 'app-popover-example',
standalone: true,
imports: [LibsUiComponentsCheckboxSingleComponent],
template: `
<libs_ui-components-checkbox-single
key="advanced-option"
[(checked)]="advancedChecked"
label="Kích hoạt chế độ nâng cao"
[popover]="advancedPopover"
[description]="advancedDescription"
[modeBorder]="true"
(outChange)="handlerChange($event)"
/>
`,
})
export class PopoverExampleComponent {
advancedChecked = signal(false);
readonly advancedPopover: IPopover = {
dataView: 'Chế độ nâng cao cho phép cấu hình thêm nhiều tùy chọn chi tiết hơn.',
config: {
direction: 'right',
} as any,
};
readonly advancedDescription: ICheckboxItemDescription = {
content: 'Lưu ý: Chế độ này yêu cầu quyền <strong>Admin</strong> mới có thể sử dụng.',
classInclude: 'text-sm text-orange-500 mt-1 ml-6',
};
handlerChange(event: ICheckboxEvent): void {
event;
console.log('advanced mode:', event.checked);
}
}4. Các trạng thái — Disable, Error, Indeterminate
import { Component, signal } from '@angular/core';
import { LibsUiComponentsCheckboxSingleComponent } from '@libs-ui/components-checkbox-single';
@Component({
selector: 'app-states-example',
standalone: true,
imports: [LibsUiComponentsCheckboxSingleComponent],
template: `
<!-- Disabled (checked) -->
<libs_ui-components-checkbox-single
label="Tùy chọn bắt buộc (không thay đổi được)"
[checked]="true"
[disable]="true"
/>
<!-- Error state với viền đỏ -->
<libs_ui-components-checkbox-single
key="required-accept"
label="Bắt buộc phải đồng ý"
[error]="true"
[showBorderError]="true"
/>
<!-- Indeterminate — còn lựa chọn khác -->
<libs_ui-components-checkbox-single
label="Chọn tất cả (một phần đã chọn)"
[stillOtherOptions]="true"
/>
<!-- Ẩn ô checkbox, chỉ hiển thị nhãn -->
<libs_ui-components-checkbox-single
label="Chỉ hiển thị nhãn"
[ignoreCheckbox]="true"
/>
`,
})
export class StatesExampleComponent {}5. Checkbox với Bullet màu và modeBorder
import { Component, signal } from '@angular/core';
import { LibsUiComponentsCheckboxSingleComponent, ICheckboxEvent, ICheckboxBullet } from '@libs-ui/components-checkbox-single';
@Component({
selector: 'app-bullet-example',
standalone: true,
imports: [LibsUiComponentsCheckboxSingleComponent],
template: `
<libs_ui-components-checkbox-single
key="status-active"
[(checked)]="activeChecked"
label="Hoạt động"
[bullet]="activeBullet"
[modeBorder]="true"
classInclude="mb-2"
(outChange)="handlerChange($event)"
/>
<libs_ui-components-checkbox-single
key="status-pending"
[(checked)]="pendingChecked"
label="Đang chờ"
[bullet]="pendingBullet"
[modeBorder]="true"
(outChange)="handlerChange($event)"
/>
`,
})
export class BulletExampleComponent {
activeChecked = signal(true);
pendingChecked = signal(false);
readonly activeBullet: ICheckboxBullet = {
backgroundColor: '#52c41a',
width: 8,
height: 8,
};
readonly pendingBullet: ICheckboxBullet = {
backgroundColor: '#faad14',
width: 8,
height: 8,
classInclude: 'rounded-full',
};
handlerChange(event: ICheckboxEvent): void {
event;
console.log('key:', event.key, 'checked:', event.checked);
}
}6. Revert trạng thái khi API thất bại
import { Component, signal, inject } from '@angular/core';
import { LibsUiComponentsCheckboxSingleComponent, ICheckboxEvent } from '@libs-ui/components-checkbox-single';
import { catchError, of } from 'rxjs';
import { takeUntilDestroyed, DestroyRef } from '@angular/core/rxjs-interop';
@Component({
selector: 'app-revert-example',
standalone: true,
imports: [LibsUiComponentsCheckboxSingleComponent],
template: `
<libs_ui-components-checkbox-single
key="newsletter"
[(checked)]="newsletterEnabled"
label="Đăng ký nhận bản tin"
(outChange)="handlerToggleNewsletter($event)"
/>
`,
})
export class RevertExampleComponent {
private readonly destroyRef = inject(DestroyRef);
newsletterEnabled = signal(false);
handlerToggleNewsletter(event: ICheckboxEvent): void {
event;
// Gọi API cập nhật, nếu thất bại thì revert trạng thái checkbox
this.settingsService.updateNewsletter(event.checked)
.pipe(
catchError(() => {
event.revert(); // Hoàn tác về trạng thái trước
return of(null);
}),
takeUntilDestroyed(this.destroyRef),
)
.subscribe();
}
// Giả lập service (trong thực tế sẽ inject thật)
private readonly settingsService = {
updateNewsletter: (enabled: boolean) => of({ success: true }),
};
}@Input()
| Input | Type | Default | Mô tả | Ví dụ |
|---|---|---|---|---|
| avatarConfig | IAvatarConfig | undefined | Cấu hình Avatar hiển thị cạnh checkbox thay cho hình ảnh thông thường | [avatarConfig]="{ linkAvatar: 'url', size: 32, textAvatar: 'AB' }" |
| bullet | ICheckboxBullet | undefined | Chấm tròn màu sắc phân loại hiển thị cạnh checkbox | [bullet]="{ backgroundColor: '#52c41a', width: 8, height: 8 }" |
| checked | boolean | false | Trạng thái chọn — hỗ trợ two-way binding qua model() | [(checked)]="isSelected" |
| classIconInclude | string | undefined | Class CSS bổ sung cho thẻ <i> chứa icon checkbox | classIconInclude="text-[20px]" |
| classImageInclude | string | undefined | Class CSS bổ sung cho thẻ <img> | classImageInclude="w-[32px] h-[32px] rounded" |
| classInclude | string | '' | Class CSS bổ sung cho container chính (wrapper) | classInclude="mb-2 w-full" |
| classLabelInclude | string | 'libs-ui-font-h5r' | Class CSS cho phần nhãn văn bản — mặc định typography h5 regular | classLabelInclude="libs-ui-font-h5m text-blue-600" |
| clickExactly | boolean | true | Khi true, chỉ click vào icon checkbox hoặc nhãn mới đổi trạng thái. Khi false, click bất kỳ vị trí nào trong container đều trigger | [clickExactly]="false" |
| componentOutlet | any | undefined | Component tùy chỉnh render thông qua ngComponentOutlet bên trong checkbox | [componentOutlet]="MyCustomBadge" |
| dataComponentOutlet | TYPE_COMPONENT_OUTLET_DATA | undefined | Dữ liệu (inputs) truyền vào component được render qua componentOutlet | [dataComponentOutlet]="{ status: 'active' }" |
| description | ICheckboxItemDescription | undefined | Mô tả chi tiết hiển thị bên dưới nhãn, hỗ trợ nội dung HTML và i18n | [description]="{ content: 'Ghi chú', classInclude: 'text-sm text-gray-500' }" |
| disable | boolean | undefined | Vô hiệu hóa toàn bộ tương tác với component | [disable]="true" |
| disableLabel | boolean | undefined | Vô hiệu hóa chỉ phần nhãn (click nhãn không đổi trạng thái checkbox) | [disableLabel]="true" |
| error | boolean | undefined | Đánh dấu checkbox ở trạng thái lỗi (icon checkbox chuyển màu đỏ) | [error]="hasError" |
| iconImageClass | string | undefined | Class icon CSS (ví dụ: từ icon font) hiển thị cạnh checkbox thay cho <img> | iconImageClass="libs-ui-icon-user" |
| ignoreCheckbox | boolean | undefined | Ẩn ô chọn icon checkbox — chỉ hiển thị nhãn, ảnh và các thành phần khác | [ignoreCheckbox]="true" |
| ignoreShowPopoverLabel | boolean | undefined | Ẩn popover khi di chuột vào nhãn (override cấu hình popover) | [ignoreShowPopoverLabel]="true" |
| imgTypeIcon | boolean | undefined | Xác định hình ảnh truyền qua linkImage là dạng icon nhỏ (18x18px) | [imgTypeIcon]="true" |
| key | string | undefined | Khóa định danh duy nhất, được gửi kèm trong sự kiện outChange để phân biệt các checkbox | key="accept-terms" |
| label | string | undefined | Văn bản nhãn hiển thị cạnh checkbox, hỗ trợ i18n key | label="Đồng ý điều khoản" hoặc label="i18n_key" |
| linkImage | string | undefined | URL hình ảnh hiển thị cạnh checkbox — hỗ trợ two-way binding qua model() | [(linkImage)]="productImageUrl" |
| linkImageError | string | undefined | URL hình ảnh dự phòng khi linkImage bị lỗi tải | linkImageError="assets/placeholder.png" |
| modeBorder | boolean | undefined | Hiển thị viền bao quanh toàn bộ component, viền xanh khi đang chọn | [modeBorder]="true" |
| popover | IPopover | undefined | Cấu hình Popover (tooltip) hiển thị khi di chuột vào phần nhãn | [popover]="{ dataView: 'Mô tả thêm', config: { direction: 'right' } }" |
| showBorderError | boolean | undefined | Hiển thị viền màu đỏ bao quanh component khi error là true | [showBorderError]="formSubmitted && !isAccepted()" |
| stillOtherOptions | boolean | undefined | Hiển thị icon trạng thái indeterminate (một phần đã chọn) thay cho checked/unchecked | [stillOtherOptions]="someSelected" |
| typeLabelPopover | TYPE_POPOVER_TYPE | 'text' | Kiểu nội dung của popover trên nhãn ('text' hoặc 'component') | typeLabelPopover="text" |
| zIndexLabel | number | 1200 | Giá trị z-index CSS cho phần nhãn và popover | [zIndexLabel]="1500" |
@Output()
| Output | Type | Mô tả | Handler TS | Binding HTML |
|---|---|---|---|---|
| (outChange) | ICheckboxEvent | Phát ra mỗi khi trạng thái checked thay đổi. Kèm theo key, checked và hàm revert() để hoàn tác nếu cần | handlerChange(event: ICheckboxEvent): void { event; /* logic */ } | (outChange)="handlerChange($event)" |
| (outChangStageFlagMousePopover) | IFlagMouse | Phát ra khi trạng thái chuột thay đổi trên vùng nhãn — dùng để đồng bộ trạng thái popover từ component cha | handlerFlagMouse(event: IFlagMouse): void { event; /* logic */ } | (outChangStageFlagMousePopover)="handlerFlagMouse($event)" |
| (outClickLabel) | void | Phát ra khi người dùng click trực tiếp vào nhãn văn bản | handlerClickLabel(): void { /* logic */ } | (outClickLabel)="handlerClickLabel()" |
| (outEventPopover) | TYPE_POPOVER_EVENT | Phát ra các sự kiện tương tác từ Popover (hover, click, close...) | handlerEventPopover(event: TYPE_POPOVER_EVENT): void { event; /* logic */ } | (outEventPopover)="handlerEventPopover($event)" |
Types & Interfaces
import {
ICheckboxEvent,
ICheckboxBullet,
ICheckboxItemDescription,
ICheckboxChecked,
} from '@libs-ui/components-checkbox-single';ICheckboxEvent
Sự kiện phát ra mỗi khi trạng thái checkbox thay đổi.
interface ICheckboxEvent {
/** Khóa định danh của checkbox (từ input [key]) */
key: any;
/** Trạng thái chọn sau khi thay đổi */
checked: boolean;
/** Danh sách các checkbox đang được chọn — dùng khi kết hợp với checkbox group */
allCheckboxChecked?: Array<ICheckboxChecked>;
/** Hàm callback để hoàn tác trạng thái về trước — ví dụ khi gọi API thất bại */
revert: () => void;
}ICheckboxBullet
Cấu hình chấm tròn màu sắc (bullet) hiển thị cạnh checkbox.
interface ICheckboxBullet {
/** Class CSS bổ sung (ví dụ: 'rounded-full') */
classInclude?: string;
/** Màu nền của bullet — bất kỳ giá trị CSS color hợp lệ */
backgroundColor: string;
/** Chiều rộng tính bằng pixel */
width: number;
/** Chiều cao tính bằng pixel */
height: number;
}ICheckboxItemDescription
Cấu hình phần mô tả chi tiết hiển thị bên dưới nhãn.
interface ICheckboxItemDescription {
/** Nội dung mô tả — hỗ trợ HTML và i18n key */
content: string;
/** Class CSS bổ sung cho thẻ wrapper của mô tả */
classInclude: string;
}ICheckboxChecked
Thông tin một checkbox đang được chọn trong context nhóm.
interface ICheckboxChecked {
/** Khóa định danh */
key: string;
/** Dữ liệu item liên quan */
item: any;
}Lưu ý quan trọng
⚠️ Hàm revert() trong outChange: Luôn lưu tham chiếu event trước khi gọi API bất đồng bộ. Gọi event.revert() trong khối catchError để hoàn tác trạng thái checkbox về trước nếu thao tác thất bại — tránh sai lệch giữa UI và server.
⚠️ clickExactly mặc định là true: Mặc định chỉ click vào icon checkbox hoặc nhãn mới trigger thay đổi. Nếu muốn toàn bộ area (card, row) có thể click, đặt [clickExactly]="false".
⚠️ description.content hỗ trợ HTML: Nội dung trong ICheckboxItemDescription.content được render qua [innerHtml] và đã qua escapeHtml bảo mật tự động. Truyền chuỗi HTML bình thường, không cần escape thủ công.
⚠️ label hỗ trợ i18n: Giá trị label được pipe qua translate tự động. Có thể truyền i18n key (label="i18n_accept_terms") hoặc chuỗi trực tiếp.
⚠️ modeBorder và trạng thái: Khi modeBorder="true", component hiển thị viền xám khi chưa chọn và viền màu primary khi đã chọn — phù hợp cho danh sách lựa chọn dạng card.
⚠️ stillOtherOptions vs checked: Hai trạng thái này độc lập. stillOtherOptions hiển thị icon indeterminate thay cho cả checked và unchecked icon — dùng để biểu thị "một phần đã chọn" trong nhóm checkbox.
Demo
npx nx serve core-uiTruy cập: http://localhost:4500/components/checkbox/single
