As we all know, Angular is a JavaScript framework used by developers for building Single Page web, desktop, and mobile applications. What did the term Single Page mean?
A single-page application (SPA) is a web application or site that communicates with the internet browser by progressively modifying the current site page with new information from the web server, rather than the default strategy for the program stacking whole new pages.
Typescript is used for Angular application development, which is a superset of JavaScript, along with CSS, HTML etc.
Everyone knows to make a similar or identical version of the original leads to copy. In this post, we will discuss How to use copy with angular? Some interesting facts about Angular is, it also supports copying. In angular we can achieve copy functionality by using utility functions like angular.copy(), angular.extend() & angular.merge(). Before delving into this we need to know what are utility functions and how it’s helpful in Angular for copying.
How do utility functions help to copy?
Like any other framework, Angular also has a series of built-in utility functions that might come in handy during development. Now take a look into what are utility functions!
A utility function defines a built-in method that is common and can be reused.
Before understanding the copy functionality, we need to walk through two important concepts: Deep Copy and Shallow Copy because the copy utility functions linger around these concepts.
Shallow Copy
Shallow Copy is a field by field copy of an object. If a field value is a reference to an object (e.g., a memory address) it copies the reference and if the field value is a primitive type it copies the value of the primitive type. Since reference is the only thing that gets copied, the changes will be visible in the other object if one object is modified.
Schematic Depiction:
Deep Copy
Everything gets duplicated in Deep Copy. In lieu of copying the references, it creates a new copy of the object and then copy the reference of the new object to the destination object. Since we are creating a completely new object and referring to it, the change made in one object is not visible to another object.
Schematic Depiction:
Where can we use shallow/deep copy?
It’s extremely simple that if the object has just crude fields, at that point clearly you will go for shallow copy, however in the event that the object has references to different objects, shallow copy or deep copy can be picked depending on the prerequisite. If the references are not changed at all, there is no reason for using deep copy, you can simply pick a shallow copy. Yet, on the off chance that the references are changed regularly, at that point you have to go for deep copy. Once more, there is no rigid principle, everything relies upon the necessity.
angular.copy() Vs angular.extend()
Well now it’s high time for our celebrated functions. Let’s look into them one by one.
- angular.copy():- It makes a deep copy of the source object or array and assigns it to a destination, where ‘destination’ is discretionary. A deep copy here means that a duplicate of the object is made. Non-enumerable properties are not considered. Only enumerable properties are considered (irrespective of source or destination).
Syntax: angular.copy( Source , [Destination] );
Source: The source that will be used to make a copy. No constraints on datatype; can use any.
Destination: Place where we copy the source to. Should be the same type as source if given explicitly.
Returns: Copy of the source, if a destination is not provided; the destination is updated with the source, if a destination is provided.
For example:
var mySource = { ‘name‘ : ‘Sakshi‘, ‘age‘ : ‘24‘, ‘obj‘ : { ‘key‘ : ‘value‘ }}
//copying single source to destination
var myDest = angular.copy(mySource);
mySource.name = “Rohit“;
console.log(mySource);
console.log(myDest);
console.log(mySource.obj === myDest.obj);
Output :- Object {name: “Rohit”, age: “24”, obj: Object}
Object {name: “Sakshi”, age: “24”, obj: Object}
false
If you check mySource.obj === myDest.obj, this will give a false result because of both points to different objects. This is called deep copying.
angular.copy() does not check whether the source and destination types are the same or not. It’s the developer’s responsibility to make sure they are compatible.
Below are some instances from the official api doc for angular.copy() which extensively talks about it.
- If a destination is not provided, a copy is created.
- If a destination is provided, everything in the destination is deleted and it is populated by everything in source.
- If the source is anything other than an object or an array (inc. null and undefined), it returns to source.
- If the source is the same as the destination, an exception is thrown.
- angular.extend():- It is used to make a shallow copy of the object. If we copy the attributes using this method, the changes made in any one of them at any point will reflect in the other as well. Also, N number of source_objects can be specified. If you want to keep the attributes of the original object, you can do that by passing an empty object as the target. This method is useful in many cases where you want to change the parent object as well as the copied object. It is mostly used during the Web Application development where the changes made should be reflected back on the customer’s site.
Syntax: angular.extend( Destination , Source1, Source2,…..);
Source: The source that will be used to make a copy. We can specify multiple source objects.
Destination: If original objects should be preserved, we need to pass an empty object as target.
var object = angular.extend({}, object1, object2).
Returns: Returns reference to destination.
For example:
var mySource = {‘name‘ : ‘Sakshi‘, ‘age‘ : ‘24‘, ‘obj‘ :{‘key‘:’value‘}}
//copying single source to destination
var myDest = angular.extend(mySource);
mySource.name = “Rohit“;
console.log(mySource);
console.log(myDest);
console.log(mySource.obj === myDest.obj);
Output :- Object { name : “Rohit”, age : “24”, obj : Object }
Object { name : “Rohit”, age : “24”, obj : Object}
True
If you check mySource.obj === myDest.obj, it will give a true result because the same reference gets pointed. This is known as shallow copying.
Now angular.extends works the same. If you pass angular.extends() first parameter (destination) an empty object, and source after that, both the objects are preserved and only the properties are copied just like angular.copy does.
Example for multiple source:
var mySource1 = {‘name’ : ‘Neha’, ‘age’ : ’26’, obj2 : {}}
var mySource2 = {‘course’ : ‘MCA’}
var myDest = {}
// copying multiple sources to destination
angular.extend(myDest, mySource1,mySource2)
console.log(myDest);
Output :- { name: “Neha”, age: “26”, course: “MCA”, obj2: Object }
Compared to angular.extend() the angular.copy() is a bit slower than the angular.extend().
Recursive merge (deep copy) is not supported by angular.extend(), angular.merge() should be used instead.
angular.merge():- deeply(recursively) extends destination object by copying enumerable properties from the source to destination. Unlike extend(), merge()descends recursively into object properties of source and does a copy.
Syntax: angular.merge( Destination , Source );
Source: The source that will be used to make a copy. We can specify multiple source objects.
Destination: You can pass an empty object as the target if you want to retain the original objects.
Returns: Returns reference to destination.
Example1:
var objA = { a : { b : ‘b‘ }};
var objB = {a : { c : ‘c‘ }};
var r = angular.merge({}, objA, objB);
console.log(r);
Output: { a: { b: “b”, c : “c” } }
Example2:
var person = { ‘Name‘ : ‘Monica‘, ‘Age‘ : ‘25‘, ‘Skills‘ : { ‘name‘ : ‘travelling‘, ‘place‘ : ‘Queenstown‘ } };
var job = { ‘Title ‘: ‘Programmer‘, ‘Experience‘ : ‘5’, ‘Skills‘ : { ‘name‘ : ‘Designing‘, ‘experience‘: ‘2‘, ‘certified‘: ‘true‘ } };
// merge from job to person
$scope.jobToperson = angular.merge(job, person);
Output: { ‘Name’: ‘Monica’, ‘Age’: ’25’, ‘Skills’: { ‘name’: ‘travelling’, ‘experience’: ‘2’, ‘certified’: ‘true’, ‘place’: ‘Queenstown’ }, ‘Title’: ‘Programmer’, ‘Experience’: ‘5’ };
If you want to preserve original objects, you can do so by passing an empty object as the target.
var object = angular.merge({}, object1, object2).
When we use copy utility functions?
angular.copy() :- angular.copy() is used when we want to retain the value of an object which we are copying to another variable. Without deep copy or using angular.copy(), changing value of property or adding any new property updates all objects referencing that same object.
angular.extend() or angular.merge() :- angular.extend() or angular.merge() is often used to achieve user options overriding default options.
For example:
function orderDrink(options) {
// Default options
var defaultOptions = { size: ‘medium’ };
// Supplied options override default options
var opts = angular.extend({}, defaultOptions, options);
console.log(opts.size);
}
Output: orderDrink({ size: ‘large’ }); // ‘large’
orderDrink(); // ‘medium’
Schematic Depiction of copy() Vs extend()
Conclusion
At last we have come up with a question, Now, which one should we use?
“Shallow copy does not copy everything. A collection structure is copied, not the elements. Two collections share the individual elements if shallow copy is used.”
“Deep copy copies everything. A deep copy of a collection results in two collections with all the elements in the original collection duplicated.”
The correct answer to the above question depends on the instances of usage as the use cases are completely different. angular.copy() and angular.extend() solves the purpose of copying the data in somewhat the same manner, the only difference lies with the referenced object. And the developer should have full liberty on this. So, now you can decide wisely which method to use when depending upon your requirements.
For more information on the topic go to Innovature’s Angular page.