npm package: @libs-ui/components-list
Description: > Component mạnh mẽ hỗ trợ hiển thị danh sách với nhiều định dạng: Text, Radio, Checkbox, Tag và Group/Tree. Kèm sub-component hiển thị giao diện No-Data linh hoạt.
Latest version: 0.2.356-23

# @libs-ui/components-list

> Component mạnh mẽ hỗ trợ hiển thị danh sách với nhiều định dạng: Text, Radio, Checkbox, Tag và Group/Tree. Kèm sub-component hiển thị giao diện No-Data linh hoạt.

**Version:** `0.2.356-3` | **Package:** `@libs-ui/components-list`

## Giới thiệu

`LibsUiComponentsListComponent` là một standalone Angular component được thiết kế để xử lý các bài toán hiển thị danh sách phức tạp. Component này không chỉ hiển thị dữ liệu mà còn tích hợp sâu với các dịch vụ lấy dữ liệu (HTTP), tìm kiếm và quản lý trạng thái chọn item.

### Tính năng

- ✅ **Đa dạng Template**: Hỗ trợ 5 loại hiển thị: `text`, `radio`, `checkbox`, `tag`, `group`.
- ✅ **Cấu trúc Cây (Group/Tree)**: Hiển thị phân cấp không giới hạn level với logic quan hệ cha-con tinh tế.
- ✅ **Tìm kiếm Thông minh**: Hỗ trợ cả tìm kiếm Online (server-side) và Offline (client-side).
- ✅ **Tích hợp HTTP**: Tự động load dữ liệu thông qua cấu hình `httpRequestData`.
- ✅ **Virtual Scroll**: Tối ưu render danh sách lớn.
- ✅ **OnPush Change Detection**: Tối ưu hiệu năng render.
- ✅ **Standalone Component**: Dễ dàng import và sử dụng.
- ✅ **Angular Signals**: State management hiện đại và reactive.
- ✅ **Custom Row/Column**: Tùy biến layout từng item qua cấu hình `rows`/`cols`.

## Khi nào sử dụng

- Khi cần hiển thị danh sách các tùy chọn cho người dùng chọn một hoặc nhiều.
- Khi xây dựng các bộ lọc (filters) có cấu trúc phân cấp phức tạp.
- Khi danh sách có kích thước lớn và cần tối ưu hiệu năng render (Virtual Scroll).
- Khi muốn đồng bộ hóa việc tìm kiếm và hiển thị dữ liệu từ API một cách tự động.

## ⚠️ Important Notes

- **Config Type**: Phải luôn cung cấp `type` và signal config tương ứng (ví dụ: `configTemplateText` cho type `text`).
- **Performance**: Virtual scroll được bật mặc định cho danh sách lớn. Tắt bằng cách set `notUseVirtualScroll: true` trong config.
- **Signals**: Các cấu hình bên trong `config` (như `httpRequestData`) phải là `WritableSignal` để component có thể reactive.
- **keysDisableItem + configCheckboxCheckAll**: Không dùng `keysDisableItem` kết hợp với template checkbox có `configCheckboxCheckAll`.

## Cài đặt

```bash
# npm
npm install @libs-ui/components-list

# yarn
yarn add @libs-ui/components-list
```

## Import

```typescript
// Component chính
import { LibsUiComponentsListComponent } from '@libs-ui/components-list';

// Sub-component No-Data (khi cần dùng riêng)
import { LibsUiComponentsListTemplatesNoDataComponent } from '@libs-ui/components-list';

@Component({
  standalone: true,
  imports: [LibsUiComponentsListComponent],
  // ...
})
export class YourComponent {}
```

## Ví dụ

### Basic (Text – Single Select)

```html
<libs_ui-components-list
  [config]="configText()"
  [keySelected]="keySelected()"
  (outSelectKey)="onSelect($event)"
  (outFunctionsControl)="onFunctionsControl($event)"></libs_ui-components-list>
```

```typescript
configText = signal<IListConfigItem>({
  type: 'text',
  httpRequestData: signal<IHttpRequestConfig>({
    objectInstance: returnListObject(myData),
    argumentsValue: [],
    functionName: 'list',
  }),
  configTemplateText: signal({
    fieldKey: 'id',
    getValue: (item) => item.name || item.label,
  }),
});
```

### Checkbox (Multi-select)

```html
<libs_ui-components-list
  [config]="configCheckbox()"
  [multiKeySelected]="multiKeySelected()"
  (outSelectMultiKey)="onMultiSelect($event)"></libs_ui-components-list>
```

```typescript
configCheckbox = signal<IListConfigItem>({
  type: 'checkbox',
  configTemplateCheckbox: signal({
    fieldKey: 'id',
    getValue: (item) => item.name,
  }),
});
```

### Tag + Search

```html
<libs_ui-components-list
  [config]="configTag()"
  [searchConfig]="{ placeholder: 'Tìm theo tên...' }"></libs_ui-components-list>
```

```typescript
configTag = signal<IListConfigItem>({
  type: 'tag',
  configTemplateTag: signal({ fieldKey: 'id', getValue: (item) => item.name }),
});
```

### Group / Tree

```typescript
import { buildListGroupConfig } from '@libs-ui/components-list';

configGroup = signal<IListConfigItem>({
  type: 'group',
  configTemplateGroup: buildListGroupConfig('group_tree_checkbox_1'),
});
```

### Custom Row & Column

```typescript
configCustomRow = signal<IListConfigItem>({
  type: 'text',
  configTemplateText: signal({
    fieldKey: 'id',
    rows: signal([
      signal({
        classRow: 'flex flex-col',
        cols: signal([signal({ getValue: (data) => of(`<b>${data.item.name}</b>`) }), signal({ getValue: (data) => of(data.item.subTitle) })]),
      }),
      signal({ getValue: (data) => of(data.item.desc) }),
    ]),
  }),
});
```

### No-Data (Default)

```html
<libs_ui-components-list-templates-no_data
  [config]="configEmpty()"
  [keySearch]="''"
  [loading]="false"
  [enableNoData]="true"></libs_ui-components-list-templates-no_data>
```

### No-Data (Custom trước khi search)

```html
<ng-template #tplNoData>
  <div class="flex flex-col items-center p-4">
    <span>Vui lòng nhập thông tin để tìm kiếm.</span>
  </div>
</ng-template>

<libs_ui-components-list-templates-no_data
  [config]="configEmpty()"
  [keySearch]="''"
  [loading]="false"
  [enableNoData]="true"
  [templateRefNotSearchNoData]="tplNoData"></libs_ui-components-list-templates-no_data>
```

### No-Result (Custom sau khi search)

```html
<ng-template
  #tplNoResult
  let-keySearch="keySearch">
  <div>
    Không có kết quả cho:
    <b>{{ keySearch }}</b>
  </div>
</ng-template>

<libs_ui-components-list-templates-no_data
  [config]="configEmpty()"
  [keySearch]="searchKeyword"
  [loading]="false"
  [enableNoData]="true"
  [templateRefSearchNoData]="tplNoResult"></libs_ui-components-list-templates-no_data>
```

## API

### libs_ui-components-list

#### Inputs

| Property                                          | Type                             | Default        | Description                                                                |
| ------------------------------------------------- | -------------------------------- | -------------- | -------------------------------------------------------------------------- |
| `autoSelectedFirstItemCallOutsideBefore`          | `boolean`                        | `false`        | Tự động chọn item đầu tiên nếu chưa có item nào được chọn.                 |
| `backgroundListCustom`                            | `string`                         | `bg-[#ffffff]` | Màu nền tùy chỉnh cho danh sách.                                           |
| `buttonsOther`                                    | `IButton[]`                      | `undefined`    | Danh sách các nút bấm khác hiển thị cuối danh sách.                        |
| `clickExactly`                                    | `boolean`                        | `undefined`    | Chỉ kích hoạt chọn khi click chính xác vào item.                           |
| `config`                                          | `IListConfigItem`                | **REQUIRED**   | Cấu hình chính (loại template, logic lấy dữ liệu...).                      |
| `disable`                                         | `boolean`                        | `false`        | Vô hiệu hóa toàn bộ component.                                             |
| `disableLabel`                                    | `boolean`                        | `false`        | Vô hiệu hóa nhãn (label).                                                  |
| `dividerClassInclude`                             | `string`                         | `undefined`    | Class CSS bổ sung cho đường kẻ phân cách.                                  |
| `dropdownTabKeyActive`                            | `string`                         | `undefined`    | Key của tab đang active trong dropdown.                                    |
| `focusInputSearch`                                | `boolean`                        | `undefined`    | Tự động focus vào ô tìm kiếm khi dữ liệu load xong.                        |
| `functionGetItemsAutoAddList`                     | `() => Array<any>`               | `undefined`    | Hàm lấy danh sách item tự động thêm vào list.                              |
| `hasButtonUnSelectOption`                         | `boolean`                        | `undefined`    | Hiển thị nút bỏ chọn tất cả.                                               |
| `hasDivider`                                      | `boolean`                        | `true`         | Hiển thị gạch phân cách giữa các phần.                                     |
| `hiddenInputSearch`                               | `boolean`                        | `false`        | Ẩn/hiện thanh tìm kiếm.                                                    |
| `ignoreClassDisableDefaultWhenUseKeysDisableItem` | `boolean`                        | `undefined`    | Bỏ class disable mặc định khi dùng `keysDisableItem`.                      |
| `isSearchOnline`                                  | `boolean`                        | `false`        | Bật tìm kiếm từ Server (call API).                                         |
| `keySearch`                                       | `string`                         | `undefined`    | Giá trị tìm kiếm khởi tạo.                                                 |
| `keySelected`                                     | `any`                            | `undefined`    | Key đang chọn (single select).                                             |
| `keysDisableItem`                                 | `Array<any>`                     | `undefined`    | Danh sách các keys bị vô hiệu hóa.                                         |
| `keysHiddenItem`                                  | `Array<any>`                     | `undefined`    | Danh sách các keys bị ẩn đi.                                               |
| `labelConfig`                                     | `ILabel`                         | `undefined`    | Cấu hình label tiêu đề cho danh sách.                                      |
| `loadingIconSize`                                 | `'large' \| 'medium' \| 'small'` | `undefined`    | Kích thước icon loading.                                                   |
| `maxItemShow`                                     | `number`                         | `undefined`    | Số lượng item tối đa hiển thị trước khi scroll.                            |
| `multiKeySelected`                                | `Array<any>`                     | `[]`           | Danh sách keys đang chọn (multi select).                                   |
| `paddingLeftItem`                                 | `boolean`                        | `undefined`    | Thêm padding bên trái cho item.                                            |
| `resetKeyWhenSelectAllKeyDropdown`                | `boolean`                        | `undefined`    | Reset key khi chọn tất cả trong dropdown.                                  |
| `searchConfig`                                    | `IInputSearchConfig`             | `{}`           | Cấu hình chi tiết cho ô tìm kiếm.                                          |
| `searchPadding`                                   | `boolean`                        | `undefined`    | Thêm padding cho thanh tìm kiếm.                                           |
| `showValidateBottom`                              | `boolean`                        | `undefined`    | Hiển thị thông báo validate ở phía dưới.                                   |
| `skipFocusInputWhenKeySearchStoreUndefined`       | `boolean`                        | `undefined`    | Bỏ qua focus input nếu `keySearchStore` là undefined.                      |
| `templateRefSearchNoData`                         | `TemplateRef`                    | `undefined`    | Template hiển thị khi tìm kiếm không có kết quả.                           |
| `templateRefNotSearchNoData`                      | `TemplateRef`                    | `undefined`    | Template hiển thị khi không trong trạng thái tìm kiếm và không có dữ liệu. |
| `validRequired`                                   | `IValidRequired`                 | `undefined`    | Cấu hình bắt buộc phải chọn item.                                          |
| `zIndex`                                          | `number`                         | `undefined`    | Z-index cho danh sách.                                                     |

#### Outputs

| Property                          | Type                                      | Description                                              |
| --------------------------------- | ----------------------------------------- | -------------------------------------------------------- |
| `(outChangeView)`                 | `Array<any>`                              | Phát ra khi danh sách hiển thị thay đổi (ví dụ sau lọc). |
| `(outChangStageFlagMousePopover)` | `IFlagMouse`                              | Phát ra trạng thái hover chuột cho popover.              |
| `(outClickButtonOther)`           | `IButton`                                 | Phát ra khi click vào các nút bấm bổ sung.               |
| `(outFieldKey)`                   | `string`                                  | Phát ra key của trường dữ liệu được chọn.                |
| `(outFunctionsControl)`           | `IListFunctionControlEvent`               | Cung cấp các method điều khiển từ bên ngoài.             |
| `(outKeySearch)`                  | `string`                                  | Phát ra khi keyword tìm kiếm thay đổi.                   |
| `(outLoadItemsComplete)`          | `{ items: Array<any>, paging?: IPaging }` | Phát ra khi việc tải dữ liệu hoàn tất.                   |
| `(outLoading)`                    | `boolean`                                 | Trạng thái đang tải dữ liệu.                             |
| `(outSelectKey)`                  | `IListDataEmitKey`                        | Phát ra khi chọn 1 item (Single Select).                 |
| `(outSelectMultiKey)`             | `IListDataEmitMultiKey`                   | Phát ra khi chọn nhiều item (Multi Select).              |
| `(outUnSelectMultiKey)`           | `Array<unknown>`                          | Phát ra danh sách các keys bị bỏ chọn.                   |

#### Methods (via `outFunctionsControl`)

| Method               | Parameters                 | Description                                                 |
| -------------------- | -------------------------- | ----------------------------------------------------------- |
| `checkIsValid()`     | `-`                        | Kiểm tra tính hợp lệ của lựa chọn (nếu có `validRequired`). |
| `getRectListView()`  | `-`                        | Lấy kích thước và vị trí của list view container.           |
| `refresh()`          | `-`                        | Làm mới danh sách và tải lại dữ liệu từ đầu.                |
| `removeItems()`      | `keys: Array<any>`         | Xóa các item cụ thể khỏi danh sách theo keys.               |
| `resetKeySelected()` | `-`                        | Xóa sạch toàn bộ các item đang được chọn.                   |
| `updateData()`       | `data: IDataUpdateToStore` | Cập nhật dữ liệu cụ thể vào store của list.                 |

### libs_ui-components-list-templates-no_data

Sub-component hiển thị giao diện trạng thái No-Data, có thể dùng độc lập hoặc tích hợp qua `[templateRefSearchNoData]` / `[templateRefNotSearchNoData]`.

#### Inputs

| Property                     | Type              | Default      | Description                                                                    |
| ---------------------------- | ----------------- | ------------ | ------------------------------------------------------------------------------ |
| `config`                     | `IListConfigItem` | **REQUIRED** | Cấu hình list (dùng để lấy `textNoData`).                                      |
| `keySearch`                  | `string`          | `''`         | Keyword đang search. Nếu rỗng → hiển thị no-data; nếu có → hiển thị no-result. |
| `loading`                    | `boolean`         | `false`      | Đang tải dữ liệu — khi `true` sẽ không hiển thị no-data.                       |
| `enableNoData`               | `boolean`         | `false`      | Bật/tắt hiển thị trạng thái no-data.                                           |
| `templateRefNotSearchNoData` | `TemplateRef`     | `undefined`  | Template tùy chỉnh khi chưa tìm kiếm (keySearch rỗng).                         |
| `templateRefSearchNoData`    | `TemplateRef`     | `undefined`  | Template tùy chỉnh khi tìm kiếm không có kết quả.                              |

## Types & Interfaces

```typescript
export type TYPE_TEMPLATE = 'checkbox' | 'group' | 'radio' | 'text' | 'tag';

export interface IListConfigItem {
  type: TYPE_TEMPLATE;
  httpRequestData?: WritableSignal<IHttpRequestConfig>;
  configTemplateText?: WritableSignal<IListConfigItemText>;
  configTemplateRadio?: WritableSignal<IListConfigItemRadio>;
  configTemplateCheckbox?: WritableSignal<IListConfigItemCheckbox>;
  configTemplateGroup?: WritableSignal<IListConfigItemGroup>;
  configTemplateTag?: WritableSignal<IListConfigItemTag>;
  textNoData?: string;
  autoSelectFirstItem?: boolean;
  sort?: (items: Array<any>) => void;
  // ...
}

export interface IListDataEmitKey {
  key: unknown;
  item: any;
  isClickManual: boolean;
}

export interface IListDataEmitMultiKey {
  keys: Array<unknown>;
  mapKeys: Array<IListDataEmitKey>;
  isClickManual: boolean;
}

export interface IListFunctionControlEvent {
  checkIsValid: () => Promise<boolean>;
  refresh: () => Promise<void>;
  resetKeySelected: () => Promise<void>;
  getRectListView: () => Promise<IBoundingClientRect>;
  removeItems: (keys: Array<string>) => Promise<void>;
  updateData: (data: IDataUpdateToStore) => Promise<void>;
}

export interface IDataUpdateToStore {
  newData: WritableSignal<Array<WritableSignal<any>>>;
  functionCustomAddDataToStore: (newData: WritableSignal<Array<WritableSignal<any>>>, store: WritableSignal<Array<WritableSignal<any>>>) => void;
}
```

## Demo

- **Local**: [http://localhost:4500/components/list](http://localhost:4500/components/list)

## Công nghệ

| Technology        | Purpose                       |
| ----------------- | ----------------------------- |
| Angular 18+       | Framework chính               |
| Angular Signals   | Quản lý state reactive        |
| TailwindCSS       | Styling hệ thống              |
| Dynamic Component | Khởi tạo template linh hoạt   |
| Virtual Scroll    | Render danh sách lớn hiệu quả |

## License

MIT