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-clone-object

v0.2.356-1

Published

> Version: `0.2.355-15` > > Pipe clone object/array với hỗ trợ shallow clone, deep clone và xử lý Signal tự động.

Readme

@libs-ui/pipes-clone-object

Version: 0.2.355-15

Pipe clone object/array với hỗ trợ shallow clone, deep clone và xử lý Signal tự động.

Giới thiệu

LibsUiPipesCloneObjectPipe là một Angular pipe đa năng để clone object hoặc array. Pipe hỗ trợ cả shallow clone (nhanh, ít memory) và deep clone (an toàn cho nested objects), đồng thờ tự động unwrap Signal nếu input là Signal.

Tính năng

  • ✅ Shallow clone với spread operator (nhanh)
  • ✅ Deep clone với lodash cloneDeep (an toàn nested)
  • ✅ Auto-unwrap Signal (không cần gọi .())
  • ✅ Default data khi input falsy
  • ✅ Hoạt động với cả object và array
  • ✅ Standalone pipe (Angular 16+)

Khi nào sử dụng

📝 Form Editing (với Cancel functionality)

Khi bạn cần chỉnh sửa data trong form nhưng muốn có khả năng Cancel để khôi phục data gốc:

// ❌ Sai: Gán trực tiếp - cùng reference
this.editUser = this.user;
this.editUser.name = 'Jane'; // ❌ user.name cũng đổi!

// ✅ Đúng: Clone trước khi edit
this.editUser = cloneDeep(this.user);
this.editUser.name = 'Jane'; // ✅ user.name không đổi
// Khi Cancel: đơn giản là bỏ editUser

🔽 Pass Data xuống Child Component

Khi truyền data xuống component con nhưng không muốn component con làm thay đổi data cha:

// Parent Component
items = ['apple', 'banana'];

// ❌ Child có thể mutate parent data
<app-child [items]="items">
// Child: items.push('orange') => Parent.items cũng đổi!

// ✅ Clone trước khi truyền
<app-child [items]="items | LibsUiPipesCloneObjectPipe">
// Child tự do modify mà không ảnh hưởng Parent

⏪ Undo/Redo Functionality

Lưu trữ các state cũ để khôi phục:

history = [cloneDeep(currentState)];

// Sau khi thay đổi
history.push(cloneDeep(newState));

// Undo: khôi phục state trước đó
currentState = cloneDeep(history[history.length - 2]);

🔄 Signal Unwrap & Clone

Đơn giản hóa template khi làm việc với Signal:

// ❌ Không dùng pipe - phải gọi .() nhiều lần
<p>{{ userSignal().name }}</p>
<p>{{ userSignal().email }}</p>

// ✅ Dùng pipe - auto unwrap + clone
@let user = (userSignal | LibsUiPipesCloneObjectPipe);
<p>{{ user.name }}</p>
<p>{{ user.email }}</p>

⚠️ Important Notes

  • 🔄 Signal Auto-Unwrap: Pipe tự động unwrap Signal nếu input là Signal. Không cần gọi .() trong template.
  • 🔀 Shallow vs Deep: Mặc định shallow clone (spread). Dùng isCloneDeep = true để deep clone nested objects.
  • 📦 Default Data: Nếu input falsy, trả về defaultData hoặc empty object {}.

Cài đặt

npm install @libs-ui/pipes-clone-object

Import

import { LibsUiPipesCloneObjectPipe } from '@libs-ui/pipes-clone-object';

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

Ví dụ

1. Shallow Clone (Mặc định)

@let cloned = (user | LibsUiPipesCloneObjectPipe);

<p>Original: {{ user.name }}</p>
<p>Cloned: {{ cloned.name }}</p>
user = { name: 'John', age: 30 };
// Shallow clone dùng spread: { ...user }
// Chỉnh sửa clone không ảnh hưởng original (top-level)

2. Deep Clone

@let cloned = (user | LibsUiPipesCloneObjectPipe : true);

<p>City: {{ cloned.address.city }}</p>
<button (click)="cloned.address.city = 'HN'">Edit</button>
user = {
  name: 'John',
  address: { city: 'HCM', country: 'VN' }
};

// Deep clone - address là object mới hoàn toàn
// An toàn khi edit nested properties

3. Clone Array

@let clonedItems = (items | LibsUiPipesCloneObjectPipe);

<ul>
  @for (item of clonedItems; track item) {
    <li>{{ item }}</li>
  }
</ul>
items = ['apple', 'banana', 'orange'];
// Array clone dùng spread: [...items]

4. 🔄 Signal Auto-Unwrap

<!-- Không cần gọi userSignal().name -->
@let cloned = (userSignal | LibsUiPipesCloneObjectPipe);
<p>Name: {{ cloned.name }}</p>
userSignal = signal({ name: 'John', age: 30 });

// Pipe tự động detect Signal và unwrap

5. Default Data

@let result = (maybeNull | LibsUiPipesCloneObjectPipe : false : { name: 'Default' });
<p>Result: {{ result.name }}</p>
maybeNull = null;
// Trả về { name: 'Default' } vì input là null

API

LibsUiPipesCloneObjectPipe

data | LibsUiPipesCloneObjectPipe : isCloneDeep? : defaultData?

Parameters

| Property | Type | Default | Description | | ------------- | ----------------------- | -------- | --------------------------------------------------------- | | data | any \| Signal<any> | - | Data cần clone (object, array, hoặc Signal). | | isCloneDeep | boolean \| undefined | false | true để deep clone, false để shallow clone. | | defaultData | any \| undefined | {} | Giá trị mặc định trả về nếu data falsy. |

Returns

any - Object/array đã được clone (hoặc defaultData nếu input falsy)

Hidden Logic

1. 🔄 Signal Auto-Unwrapping

Pipe sử dụng isSignal() từ @angular/core để detect và auto-unwrap Signal:

if (isSignal(data)) {
  data = data(); // Auto-unwrap
}
return isCloneDeep ? cloneDeep(data) : { ...data };

So sánh:

// ❌ Không dùng pipe - phải unwrap thủ công
{{ userSignal().name }}

// ✅ Dùng pipe - auto unwrap
@let cloned = (userSignal | LibsUiPipesCloneObjectPipe);
{{ cloned.name }}

2. 🔀 Shallow vs Deep Clone

| Loại | Cách làm | Pros | Cons | | ---- | -------- | ---- | ---- | | Shallow | { ...obj } hoặc [ ...arr ] | Nhanh, ít memory | Nested objects share reference | | Deep | cloneDeep(obj) | An toàn toàn bộ | Chậm hơn, nhiều memory |

// Shallow - nested vẫn share reference
const shallow = { ...user };
shallow.name = 'Jane'; // ✅ Không ảnh hưởng original
shallow.address.city = 'HN'; // ❌ Ảnh hưởng original!

// Deep - hoàn toàn independent
const deep = cloneDeep(user);
deep.address.city = 'HN'; // ✅ Không ảnh hưởng original

3. 📦 Default Data Handling

Khi input là falsy, pipe trả về defaultData hoặc empty object:

// Các trường hợp return default
transform(null)           => defaultData || {}
transform(undefined)      => defaultData || {}
transform(0)              => defaultData || {}
transform('')             => defaultData || {}

// Với custom defaultData
transform(null, false, { name: 'Guest' })
// => { name: 'Guest' }

Demo

Unit Tests

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

License

MIT