npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@libs-ui/pipes-convert-object-to-signal

v0.2.356-25

Published

> Version: `0.2.355-15` > > Pipe chuyển đổi object/array thành cấu trúc Signals lồng nhau để tận dụng fine-grained reactivity.

Readme

@libs-ui/pipes-convert-object-to-signal

Version: 0.2.355-15

Pipe chuyển đổi object/array thành cấu trúc Signals lồng nhau để tận dụng fine-grained reactivity.

Giới thiệu

LibsUiPipesConvertObjectToSignalPipe chuyển đổi một object hoặc array thành cấu trúc Signals lồng nhau (nested signals). Mỗi property của object trở thành một Signal riêng biệt, cho phép Angular chỉ re-render các phần UI thực sự thay đổi thay vì cả component.

Tính năng

  • ✅ Chuyển object thành nested WritableSignals
  • ✅ Chuyển array thành Signal chứa các Signal items
  • ✅ Deep clone mặc định (an toàn)
  • ✅ Hỗ trợ nested objects (multi-level)
  • ✅ Fine-grained reactivity - tối ưu performance

Khi nào sử dụng

📝 Form với nhiều fields

Khi form có nhiều field, dùng nested signals để thay đổi một field không ảnh hưởng đến các field khác:

// ❌ Nguyên object là Signal - không hiệu quả
user = signal({ name: 'John', email: '[email protected]' });
// user.set({ ...user(), name: 'Jane' }) => Cả name và email đều trigger re-render!

// ✅ Nested Signals - hiệu quả
user = { name: 'John', email: '[email protected]' } | LibsUiPipesConvertObjectToSignalPipe;
user().name.set('Jane'); // => Chỉ name trigger re-render

📊 Data table lớn

Trong bảng dữ liệu lớn, chỉ re-render cell thay đổi thay vì cả row:

rows = data | LibsUiPipesConvertObjectToSignalPipe;

// Trong template
@for (row of rows(); track row().id) {
  <tr>
    <td>{{ row().name() }}</td> <!-- Chỉ re-render khi name thay đổi -->
    <td>{{ row().email() }}</td> <!-- Không re-render khi name thay đổi -->
  </tr>
}

🔄 Two-way binding tối ưu

Dễ dàng bind từng property đến component con:

<app-input-field 
  [value]="user().name()"
  (change)="user().name.set($event)"
/>
<app-input-field 
  [value]="user().email()"
  (change)="user().email.set($event)"
/>

⚠️ Important Notes

  • 🔄 Nested Signals: Mỗi property của object trở thành một Signal. Thay đổi một property chỉ trigger re-render ở component sử dụng property đó.
  • 🔀 Shallow vs Deep Clone: Mặc định deep clone để tránh mutate data gốc. Dùng isCloneDeep = false để giữ nguyên reference.
  • ⚡ Fine-grained Reactivity: Hiệu quả hơn so với nguyên object làm Signal vì chỉ re-render khi property cụ thể thay đổi.

Cài đặt

npm install @libs-ui/pipes-convert-object-to-signal

Import

import { LibsUiPipesConvertObjectToSignalPipe } from '@libs-ui/pipes-convert-object-to-signal';

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

Ví dụ

1. Object thành Nested Signals

@let user = ({ name: 'John', email: '[email protected]', age: 30 } | LibsUiPipesConvertObjectToSignalPipe);

<div>
  <input [value]="user().name()" (input)="user().name.set($event.target.value)" />
  <input [value]="user().email()" (input)="user().email.set($event.target.value)" />
</div>

<p>Name: {{ user().name() }}</p>
<p>Email: {{ user().email() }}</p>
// user() trả về object với mỗi property là WritableSignal
// user().name() - lấy giá trị
// user().name.set('Jane') - set giá trị mới

2. Array thành Signal của Signals

@let items = (['apple', 'banana', 'orange'] | LibsUiPipesConvertObjectToSignalPipe);

<ul>
  @for (item of items(); track $index) {
    <li>
      <input [value]="item()" (input)="item.set($event.target.value)" />
    </li>
  }
</ul>
// items() là WritableSignal<WritableSignal<string>[]>
// items()[0]() - lấy giá trị item đầu tiên
// items()[0].set('new') - set giá trị mới

3. Nested Object

@let company = ({
  name: 'Tech Corp',
  ceo: { name: 'John', age: 45 }
} | LibsUiPipesConvertObjectToSignalPipe);

<input [value]="company().name()" (input)="company().name.set($event.target.value)" />
<input [value]="company().ceo().name()" (input)="company().ceo().name.set($event.target.value)" />

<p>Company: {{ company().name() }}</p>
<p>CEO: {{ company().ceo().name() }}</p>

4. Giữ nguyên Reference (nhanh hơn)

@let user = (userData | LibsUiPipesConvertObjectToSignalPipe : false);

<p>Name: {{ user().name() }}</p>
// isCloneDeep = false: Giữ nguyên reference đến data gốc
// Nhanh hơn nhưng cẩn thận mutate!

API

LibsUiPipesConvertObjectToSignalPipe

data | LibsUiPipesConvertObjectToSignalPipe : isCloneDeep?

Parameters

| Property | Type | Default | Description | | ------------- | ----------------------- | -------- | --------------------------------------------------------- | | data | any | - | Object/array cần chuyển đổi thành Signals. | | isCloneDeep | boolean \| undefined | true | true để deep clone (an toàn), false để giữ reference. |

Returns

Nested structure với WritableSignals:

// Object -> WritableSignal<{ prop: WritableSignal<...> }>
// Array -> WritableSignal<WritableSignal<T>[]>

Hidden Logic

1. 🔄 Fine-grained Reactivity

Khác với nguyên object làm Signal, nested signals chỉ re-render component khi property cụ thể thay đổi:

// ❌ Object là signal
user = signal({ name: 'John', email: '[email protected]' });
user.set({ ...user(), name: 'Jane' });
// => Cả name và email đều trigger re-render!

// ✅ Nested signals
user = object | LibsUiPipesConvertObjectToSignalPipe;
user().name.set('Jane');
// => Chỉ name trigger re-render, email không!

2. 🔀 Shallow vs Deep Clone

| Tùy chọn | Behavior | Khi nào dùng | | -------- | -------- | ------------ | | true (default) | Deep clone data trước khi convert | Luôn an toàn, không mutate gốc | | false | Giữ nguyên reference | Performance critical, chắc chắn không mutate |

// Deep clone (default) - An toàn
user = userData | LibsUiPipesConvertObjectToSignalPipe;
user().name.set('Jane'); // Không ảnh hưởng userData

// No clone - Nhanh hơn
user = userData | LibsUiPipesConvertObjectToSignalPipe : false;
user().name.set('Jane'); // Cẩn thận: ảnh hưởng userData!

3. 📦 Các kiểu dữ liệu được hỗ trợ

| Kiểu dữ liệu | Kết quả | | ------------ | ------- | | Primitives (string, number, boolean) | Trả về nguyên (không convert) | | Object | WritableSignal với mỗi property là Signal | | Array | WritableSignal chứa array của Signals | | Map/Set | Được xử lý đặc biệt | | Promise/Observer | Trả về nguyên (async objects) | | null/undefined | Trả về nguyên |

123 | pipe => 123 (primitive)
{ name: 'John' } | pipe => WritableSignal<...> (object)
['a', 'b'] | pipe => WritableSignal<WritableSignal<string>[]> (array)
Promise/Observer | pipe => Trả về nguyên (async)

Demo

Unit Tests

Xem file test-commands.md để biết cách chạy unit tests.

License

MIT