Actually, using Angular2 doesn't restrict you from using other libraries like jQuery for deep copying objects with their $.clone() function or lodash with _.cloneDeep().
The most common libraries have their typings available via typings CLI tools so even when transpiling from TypeScript you can seamlessly use anything you want.
/**
* Returns a deep copy of the object
*/
public static deepCopy(oldObj: any) {
var newObj = oldObj;
if (oldObj && typeof oldObj === "object") {
if (oldObj instanceof Date) {
return new Date(oldObj.getTime());
}
newObj = Object.prototype.toString.call(oldObj) === "[object Array]" ? [] : {};
for (var i in oldObj) {
newObj[i] = this.deepCopy(oldObj[i]);
}
}
return newObj;
}
I am faced with the problem of deep copying. angular.copy({}, factory) and angular.extend({}, factory) helps well for array or hashes objects, but when copying an object a calass, sometimes there may be problems with connected dependencies. I solved this problem so:
export class DeepCopy {
static copy(data: any, objMap?: WeakMap<any, any>) {
if (!objMap) {
// Map for handle recursive objects
objMap = new WeakMap();
}
// recursion wrapper
const deeper = value => {
if (value && typeof value === 'object') {
return DeepCopy.copy(value, objMap);
}
return value;
};
// Array value
if (Array.isArray(data)) return data.map(deeper);
// Object value
if (data && typeof data === 'object') {
// Same object seen earlier
if (objMap.has(data)) return objMap.get(data);
// Date object
if (data instanceof Date) {
const result = new Date(data.valueOf());
objMap.set(data, result);
return result;
}
// Use original prototype
const node = Object.create(Object.getPrototypeOf(data));
// Save object to map before recursion
objMap.set(data, node);
for (const [key, value] of Object.entries(data)) {
node[key] = deeper(value);
}
return node;
}
// Scalar value
return data;
}
}
I faced the same issue and created an npm package for the same. I know its an overhead just for this functionality :) . I plan to add more to this package over time. This one has been tested on 10.1.6 version of Angular. It should definitely work with versions higher than 10.1.6. Usage details are mentioned on the npm package page.
Some of the answers here rely on lodash which can cause issues when imported in angular 10+ with a warning message like the following:
WARNING in xxxxx.ts depends on lodash/cloneDeep. CommonJS or AMD dependencies can cause optimization bailouts.
Other answers use parsing via JSON or try to roll their own implementation. Not to roll ours, we use clone: a lightweight clone utility with limited dependencies.
In order to use clone, you just need to install these two packages:
The create a service (the service is not mandatory, but I prefer this approach) that uses the clone API:
import { Injectable } from '@angular/core';
import * as clone from 'clone';
@Injectable()
export class ObjectCloneService {
public cloneObject<T>(value: T): T {
return clone<T>(value);
}
}