Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

deep merge objects with AngularJS

Normally to shallow copy objects I would use angular.extend()

Here's an example of that:

var object1 = {   "key": "abc123def456",   "message": {     "subject": "Has a Question",     "from": "[email protected]",     "to": "[email protected]"    } };  var object2 = {   "key": "00700916391" };  console.log(angular.extend({}, object1, object2)); 

Would give us:

{  "key": "00700916391",  "message": {    "subject": "Has a Question",    "from": "[email protected]",    "to": "[email protected]"   } } 

But what if I wanted to merge objects so that parent keys are not over written by child objects:

var object1 = {   "key": "abc123def456",   "message": {     "subject": "Has a Question",     "from": "[email protected]",     "to": "[email protected]"    } };  var object2 = {   "key": "00700916391",              //Overwrite me   "message": {                       //Dont overwrite me!     "subject": "Hey what's up?",     //Overwrite me     "something": "something new"     //Add me    } };  console.log(merge(object1, object2)); 

Would give us:

{  "key": "00700916391",  "message": {    "subject": "Hey what's up?",    "from": "[email protected]",    "to": "[email protected]",    "something": "something new"   } } 
  • Is there an Angular function that already does a deep merge that I am not aware of?

  • If not is there a native way to do this in javascript recursively for n levels deep?

like image 884
Dan Kanze Avatar asked Jun 21 '13 19:06

Dan Kanze


People also ask

How to merge two objects in AngularJS?

You can specify multiple src objects. 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) .

What is deep merge?

Deep merging ensures that all levels of the objects we merge into another object are copied instead of referencing the original objects.

How do I merge two objects in TypeScript?

Use the spread syntax (...) to merge objects in TypeScript, e.g. const obj3 = { ... obj1, ... obj2 } . The type of the final object will successfully be inferred, so trying to add or remove properties from it will cause the type checker to show an error.


2 Answers

Angular 1.4 or later

Use angular.merge:

Unlike extend(), merge() recursively descends into object properties of source objects, performing a deep copy.

angular.merge(object1, object2); // merge object 2 into object 1 

Older versions of Angular:

There is no reason a simple recursive algorithm shouldn't work :)

Assuming they're both the result of JSON.stringify or similar:

function merge(obj1,obj2){ // Our merge function     var result = {}; // return result     for(var i in obj1){      // for every property in obj1          if((i in obj2) && (typeof obj1[i] === "object") && (i !== null)){             result[i] = merge(obj1[i],obj2[i]); // if it's an object, merge            }else{            result[i] = obj1[i]; // add it to result         }     }     for(i in obj2){ // add the remaining properties from object 2         if(i in result){ //conflict             continue;         }         result[i] = obj2[i];     }     return result; } 

Here is a working fiddle

(Note, arrays are not handled here)

like image 158
Benjamin Gruenbaum Avatar answered Sep 30 '22 15:09

Benjamin Gruenbaum


In the new version of Angularjs they added merge function which will perform the deep copy.

For the older versions, I have created my custom function by copying the code of merge function from new version of Angularjs. Below is the code for the same,

function merge(dst){   var slice = [].slice;   var isArray = Array.isArray;   function baseExtend(dst, objs, deep) {     for (var i = 0, ii = objs.length; i < ii; ++i) {       var obj = objs[i];       if (!angular.isObject(obj) && !angular.isFunction(obj)) continue;       var keys = Object.keys(obj);       for (var j = 0, jj = keys.length; j < jj; j++) {         var key = keys[j];         var src = obj[key];         if (deep && angular.isObject(src)) {           if (!angular.isObject(dst[key])) dst[key] = isArray(src) ? [] : {};           baseExtend(dst[key], [src], true);         } else {           dst[key] = src;         }       }     }      return dst;   }   return baseExtend(dst, slice.call(arguments, 1), true); } 

Hope this will help someone who is wondering why angular.merge is not working in older versions.

like image 31
Mathankumar Avatar answered Sep 30 '22 15:09

Mathankumar