npm package: @libs-ui/pipes-check-selected-by-key
Description: > Pipe kiểm tra xem một giá trị có tồn tại trong mảng các key đã chọn hay không.
Latest version: 0.2.356-23

# @libs-ui/pipes-check-selected-by-key

> Pipe kiểm tra xem một giá trị có tồn tại trong mảng các key đã chọn hay không.

**Version:** 0.2.355-14

## Giới thiệu

`LibsUiPipesCheckSelectedByKeyPipe` là một Angular pipe đơn giản nhưng hữu ích để kiểm tra xem một giá trị có tồn tại trong mảng các key đã được chọn hay không. Pipe này thường được sử dụng trong các trường hợp multi-select, checkbox lists, hoặc bất kỳ tình huống nào cần kiểm tra trạng thái "đã chọn" của một item.

### Tính năng

- ✅ Kiểm tra nhanh sự tồn tại của giá trị trong mảng
- ✅ Hỗ trợ mọi kiểu dữ liệu (string, number, object)
- ✅ Validation an toàn với null/undefined
- ✅ Pure pipe - hiệu suất cao
- ✅ Standalone - dễ dàng import

## Khi nào sử dụng

- Kiểm tra xem một item có được chọn trong danh sách multi-select hay không
- Hiển thị trạng thái selected/unselected trong UI (checkbox, highlight)
- Filter hoặc validate dữ liệu dựa trên danh sách keys đã chọn
- Xác định xem một key có trong collection hay không

## ⚠️ Important Notes

- **🔄 Tham số length - Pure Pipe Trigger**: Đây là pattern quan trọng để đảm bảo pipe chạy lại khi mảng thay đổi. Vì đây là pure pipe, nó chỉ chạy lại khi reference thay đổi. Nếu bạn `push`/`pop` phần tử vào mảng (mutate) mà giữ nguyên reference, pipe sẽ không tự chạy lại. Tham số `length` buộc pipe phải re-run khi số lượng phần tử thay đổi.
- **Kiểm tra null/undefined**: Pipe trả về `false` nếu `multiKeys` là `null`, `undefined`, không phải array, hoặc array rỗng.
- **So sánh strict**: Sử dụng `===` để so sánh, không có type coercion.

## Cài đặt

```bash
npm install @libs-ui/pipes-check-selected-by-key
```

## Import

```typescript
import { LibsUiPipesCheckSelectedByKeyPipe } from '@libs-ui/pipes-check-selected-by-key';

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

## Ví dụ

### Cách sử dụng cơ bản

```html
<!-- Kiểm tra xem 'apple' có trong selectedFruits không -->
<div [class.selected]="'apple' | LibsUiPipesCheckSelectedByKeyPipe : selectedFruits : selectedFruits.length">Apple {{ ('apple' | LibsUiPipesCheckSelectedByKeyPipe : selectedFruits : selectedFruits.length) ? '✓' : '' }}</div>
```

```typescript
selectedFruits = ['apple', 'banana'];
// Kết quả: true (vì 'apple' có trong mảng)
```

### Sử dụng với \*ngFor

```html
<div *ngFor="let fruit of allFruits">
  <div [class.active]="fruit.id | LibsUiPipesCheckSelectedByKeyPipe : selectedIds : selectedIds.length">{{ fruit.name }}</div>
</div>
```

### Sử dụng với số

```html
<div [class.active]="42 | LibsUiPipesCheckSelectedByKeyPipe : selectedIds : selectedIds.length">Item 42</div>
```

```typescript
selectedIds = [1, 42, 100];
// Kết quả: true
```

### Edge Cases

```html
<!-- Mảng rỗng -->
{{ 'apple' | LibsUiPipesCheckSelectedByKeyPipe : [] : 0 }}
<!-- Kết quả: false -->

<!-- multiKeys undefined -->
{{ 'apple' | LibsUiPipesCheckSelectedByKeyPipe : undefined : undefined }}
<!-- Kết quả: false -->
```

## API

### LibsUiPipesCheckSelectedByKeyPipe

```typescript
value | LibsUiPipesCheckSelectedByKeyPipe : multiKeys : length
```

#### Parameters

| Property    | Type                      | Default | Description                                                        |
| ----------- | ------------------------- | ------- | ------------------------------------------------------------------ |
| `value`     | `any`                     | -       | Giá trị cần kiểm tra                                               |
| `multiKeys` | `Array<any> \| undefined` | -       | Mảng các key đã được chọn                                          |
| `length`    | `number \| undefined`     | -       | **Pure Pipe Trigger** - Truyền `multiKeys.length` để đảm bảo pipe chạy lại khi mảng thay đổi số lượng phần tử |

#### Returns

`boolean` - `true` nếu `value` tồn tại trong `multiKeys`, ngược lại `false`

## Hidden Logic

### 1. 🔄 Pure Pipe Trigger Pattern (Tham số `length`)

Tham số `length` là một **trigger parameter** quan trọng để giải quyết vấn đề của pure pipe trong Angular:

**Vấn đề**: Angular pure pipe chỉ chạy lại khi reference của input thay đổi. Nếu bạn mutate mảng (dùng `push`, `pop`, `splice`) mà vẫn giữ nguyên reference, pipe sẽ không tự động chạy lại.

**Giải pháp**: Truyền `length` như một tham số riêng. Khi số lượng phần tử thay đổi, Angular detect change và buộc pipe phải chạy lại.

**🔴 QUAN TRỌNG - `length` PHẢI được trích xuất chính xác từ `multiKeys.length`:**

```typescript
// ✅ Đúng: Truyền multiKeys.length
'apple' | LibsUiPipesCheckSelectedByKeyPipe : selectedFruits : selectedFruits.length

// ❌ Sai: Truyền sai length
'apple' | LibsUiPipesCheckSelectedByKeyPipe : selectedFruits : 0
// => false (mặc dù 'apple' có trong mảng!)
```

**Cách hoạt động:**

```typescript
// 1. Khi mutate array (push/pop), reference không đổi
this.selectedKeys.push('new-key'); // Cùng reference

// 2. Nhưng nhờ truyền selectedKeys.length, Angular detect change
// Template: value | pipe : selectedKeys : selectedKeys.length
// => Pipe chạy lại vì length thay đổi

// 3. Validation trong source code
if (!multiKeys || !(multiKeys instanceof Array) || !multiKeys.length || !length) {
  return false; // ❌ Return false nếu length không khớp
}
```

### 2. Validation đầu vào

Pipe có logic validation phức tạp để đảm bảo an toàn khi xử lý các giá trị null/undefined:

```typescript
// Các trường hợp trả về false:
// 1. multiKeys là null hoặc undefined
// 2. multiKeys không phải là Array
// 3. multiKeys.length === 0
// 4. length parameter là falsy (0, null, undefined)

// Edge case:
// Nếu length = 0 nhưng multiKeys có phần tử
// Pipe vẫn trả về false (do check !length)
const result = 'apple' | pipe : ['apple'] : 0;
// => false (mặc dù 'apple' có trong array)
```

### 3. So sánh Strict Equality

Pipe sử dụng strict equality (`===`) để so sánh, không có type coercion:

```typescript
// String vs Number
'42' | pipe : [42] : 1  // => false

// Object reference
const obj = { id: 1 };
obj | pipe : [obj] : 1  // => true
obj | pipe : [{ id: 1 }] : 1  // => false (khác reference)
```

## Demo

**Local:** http://localhost:4500/pipes/check-selected-by-key

**Production:** https://your-domain.com/pipes/check-selected-by-key

## License

MIT