@libs-ui/pipes-get-value-of-object
v0.2.357-9
Published
> Pipe truy cập giá trị object theo đường dẫn chuỗi (dot/bracket notation), hỗ trợ nested path an toàn và giá trị mặc định.
Readme
@libs-ui/pipes-get-value-of-object
Pipe truy cập giá trị object theo đường dẫn chuỗi (dot/bracket notation), hỗ trợ nested path an toàn và giá trị mặc định.
Giới thiệu
LibsUiPipesGetValueOfObjectPipe cho phép truy cập thuộc tính lồng nhau của object trực tiếp trong template Angular thông qua chuỗi path ("a.b.c", "items[0].name"). Pipe tích hợp hàm get từ @libs-ui/utils, tự động xử lý null/undefined ở mọi cấp độ mà không gây lỗi runtime. Phù hợp cho các cấu trúc dữ liệu động hoặc config được truy cập qua path dạng string.
Tính năng
- ✅ Truy cập thuộc tính lồng nhau an toàn (không throw khi gặp null/undefined giữa đường)
- ✅ Hỗ trợ dot notation:
"user.profile.name" - ✅ Hỗ trợ bracket/array notation:
"items[0].id"hoặc"items.0.id" - ✅ Hỗ trợ path mảng dạng chuỗi kết hợp:
"data.list[2].label" - ✅ Cung cấp
defaultValuekhi path không tồn tại hoặc giá trị làundefined - ✅ Hỗ trợ
keepLastValueIfSignalđể lấy signal thô thay vì unwrap giá trị - ✅ Standalone pipe — import trực tiếp vào component, không cần module
Khi nào sử dụng
- Cần truy cập nested property từ object có cấu trúc phức tạp mà không muốn viết optional chaining dài trong template
- Path đến thuộc tính được xác định dưới dạng chuỗi động (vd: từ config, từ API response)
- Cần hiển thị giá trị mặc định khi property không tồn tại trong object
- Làm gọn template khi render bảng/list từ data schema không cố định
- Truy cập phần tử trong mảng theo index thông qua path string
Cài đặt
npm install @libs-ui/pipes-get-value-of-objectImport
import { LibsUiPipesGetValueOfObjectPipe } from '@libs-ui/pipes-get-value-of-object';
@Component({
standalone: true,
imports: [LibsUiPipesGetValueOfObjectPipe],
// ...
})
export class MyComponent {}Ví dụ sử dụng
1. Truy cập thuộc tính đơn giản
import { Component } from '@angular/core';
import { LibsUiPipesGetValueOfObjectPipe } from '@libs-ui/pipes-get-value-of-object';
@Component({
standalone: true,
imports: [LibsUiPipesGetValueOfObjectPipe],
template: `
<p>Tên: {{ user | LibsUiPipesGetValueOfObjectPipe:'name' }}</p>
<p>Email: {{ user | LibsUiPipesGetValueOfObjectPipe:'email':'Chưa có email' }}</p>
`,
})
export class UserCardComponent {
user = {
name: 'Nguyễn Văn A',
role: 'admin',
};
// Kết quả: "Tên: Nguyễn Văn A"
// Kết quả: "Email: Chưa có email" ← dùng defaultValue vì email không tồn tại
}2. Truy cập thuộc tính lồng nhau
import { Component } from '@angular/core';
import { LibsUiPipesGetValueOfObjectPipe } from '@libs-ui/pipes-get-value-of-object';
@Component({
standalone: true,
imports: [LibsUiPipesGetValueOfObjectPipe],
template: `
<p>Thành phố: {{ profile | LibsUiPipesGetValueOfObjectPipe:'address.city' }}</p>
<p>Quốc gia: {{ profile | LibsUiPipesGetValueOfObjectPipe:'address.country':'Không rõ' }}</p>
<p>Zip: {{ profile | LibsUiPipesGetValueOfObjectPipe:'address.zip':'N/A' }}</p>
`,
})
export class ProfileCardComponent {
profile = {
name: 'Trần Thị B',
address: {
city: 'Hà Nội',
country: 'Việt Nam',
// zip không tồn tại
},
};
// Kết quả: "Thành phố: Hà Nội"
// Kết quả: "Quốc gia: Việt Nam"
// Kết quả: "Zip: N/A"
}3. Truy cập phần tử trong mảng
import { Component } from '@angular/core';
import { LibsUiPipesGetValueOfObjectPipe } from '@libs-ui/pipes-get-value-of-object';
@Component({
standalone: true,
imports: [LibsUiPipesGetValueOfObjectPipe],
template: `
<!-- Truy cập bằng dot notation -->
<p>Tag đầu: {{ data | LibsUiPipesGetValueOfObjectPipe:'tags.0' }}</p>
<!-- Truy cập bằng bracket notation -->
<p>Tag thứ hai: {{ data | LibsUiPipesGetValueOfObjectPipe:'tags[1]' }}</p>
<!-- Kết hợp path phức tạp -->
<p>Tên sản phẩm đầu: {{ data | LibsUiPipesGetValueOfObjectPipe:'products[0].name':'Không có sản phẩm' }}</p>
`,
})
export class ProductListComponent {
data = {
tags: ['Angular', 'TypeScript', 'RxJS'],
products: [
{ id: 1, name: 'Laptop Pro', price: 25000000 },
{ id: 2, name: 'Chuột không dây', price: 350000 },
],
};
// Kết quả: "Tag đầu: Angular"
// Kết quả: "Tag thứ hai: TypeScript"
// Kết quả: "Tên sản phẩm đầu: Laptop Pro"
}4. Dùng trong @for để render bảng cấu hình động
import { Component } from '@angular/core';
import { LibsUiPipesGetValueOfObjectPipe } from '@libs-ui/pipes-get-value-of-object';
@Component({
standalone: true,
imports: [LibsUiPipesGetValueOfObjectPipe],
template: `
<table>
<tr>
@for (col of columns; track col.key) {
<th>{{ col.label }}</th>
}
</tr>
@for (row of rows; track row.id) {
<tr>
@for (col of columns; track col.key) {
<td>{{ row | LibsUiPipesGetValueOfObjectPipe:col.key:'—' }}</td>
}
</tr>
}
</table>
`,
})
export class DynamicTableComponent {
columns = [
{ key: 'name', label: 'Họ tên' },
{ key: 'info.email', label: 'Email' },
{ key: 'info.phone', label: 'Điện thoại' },
];
rows = [
{ id: 1, name: 'Lê Văn C', info: { email: '[email protected]' } },
{ id: 2, name: 'Phạm Thị D', info: { email: '[email protected]', phone: '0912345678' } },
];
// Cột "Điện thoại" của Lê Văn C sẽ hiển thị "—" vì info.phone không tồn tại
}5. Sử dụng standalone qua pipe.transform() trong TypeScript
import { LibsUiPipesGetValueOfObjectPipe } from '@libs-ui/pipes-get-value-of-object';
const pipe = new LibsUiPipesGetValueOfObjectPipe();
const user = {
profile: {
displayName: 'Admin User',
roles: ['admin', 'editor'],
},
};
// Lấy giá trị nested
const name = pipe.transform(user, 'profile.displayName');
// → 'Admin User'
// Lấy phần tử mảng
const firstRole = pipe.transform(user, 'profile.roles.0');
// → 'admin'
// Dùng defaultValue khi path không tồn tại
const avatar = pipe.transform(user, 'profile.avatar', 'default-avatar.png');
// → 'default-avatar.png'
// Path không tồn tại, không có defaultValue
const missing = pipe.transform(user, 'profile.age');
// → undefinedTransform
| Tham số | Type | Bắt buộc | Mô tả | Ví dụ |
|---|---|---|---|---|
| object | Record<any, any> | ✅ | Object nguồn cần truy cập giá trị | userObj |
| path | string | ✅ | Đường dẫn đến thuộc tính (dot hoặc bracket notation) | 'profile.name', 'items[0].id' |
| defaultValue | any | ❌ | Giá trị trả về khi path không tồn tại hoặc giá trị là undefined | 'N/A', 0, [] |
| keepLastValueIfSignal | boolean | ❌ | Khi true, trả về signal thô thay vì unwrap giá trị — dùng nội bộ cho Signal workflow | true |
Cú pháp template:
{{ object | LibsUiPipesGetValueOfObjectPipe:'path' }}
{{ object | LibsUiPipesGetValueOfObjectPipe:'path':'defaultValue' }}
{{ object | LibsUiPipesGetValueOfObjectPipe:'path':defaultValue:keepLastValueIfSignal }}Cú pháp standalone (TypeScript):
const pipe = new LibsUiPipesGetValueOfObjectPipe();
pipe.transform(object, 'path');
pipe.transform(object, 'path', 'defaultValue');
pipe.transform(object, 'path', 'defaultValue', false);Hành vi với các trường hợp đặc biệt
| Input object | Input path | defaultValue | Kết quả |
|---|---|---|---|
| { a: { b: 1 } } | 'a.b' | — | 1 |
| { a: { b: 1 } } | 'a.c' | 'fallback' | 'fallback' |
| { a: { b: 1 } } | 'a.c' | — | undefined |
| { a: { b: null } } | 'a.b' | 'fallback' | 'fallback' (giá trị null cũng áp dụng defaultValue) |
| null | 'any.path' | 'default' | 'default' |
| undefined | 'any.path' | 0 | 0 |
| { tags: ['a','b'] } | 'tags.0' | — | 'a' |
| { tags: ['a','b'] } | 'tags[1]' | — | 'b' |
| { tags: ['a','b'] } | 'tags[5]' | 'missing' | 'missing' |
| { x: 1 } | '' (chuỗi rỗng) | — | { x: 1 } (trả về chính object) |
Lưu ý quan trọng
⚠️ Pipe name là PascalCase: Tên pipe trong template là LibsUiPipesGetValueOfObjectPipe (không phải getValueOfObject hay dạng camelCase). Cần import đúng class này vào imports[] của component.
⚠️ Path dạng chuỗi: Tham số path PHẢI là string literal hoặc biến string — không được truyền object/array trực tiếp làm path.
⚠️ null và undefined đều áp dụng defaultValue: Khác với nhiều thư viện lodash-style, pipe dùng toán tử ?? ở bước trả về cuối cùng — vì vậy khi giá trị tại path là null HOẶC undefined, pipe đều trả về defaultValue (nếu có truyền), không phân biệt hai loại giá trị này.
⚠️ keepLastValueIfSignal chỉ dùng nội bộ: Tham số thứ tư dành cho các workflow Signal nội bộ của @libs-ui/utils. Không dùng trong code ứng dụng thông thường.
⚠️ Không gọi function trong template: Không dùng {{ getValueFromObj(user, 'name') }} — hãy dùng pipe để tránh gọi function mỗi change detection cycle.
