Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angularjs - extend recursive

Tags:

angularjs

I would like to extend some properties recursive (aka. deep copy). much like jQuery does. I'm not including jquery only b/c of one thing.

jQuery.extend( true, target, object1 )

is there any elegant way you know of that does it with simple javascript or angularjs?

update please take a look and try to accomplish the same result http://plnkr.co/edit/GHabYbyhsqtfBPtplksO?p=preview

i did look into .copy() but the "properties (for objects) are deleted"

like image 255
Endless Avatar asked Mar 09 '13 12:03

Endless


4 Answers

Here is an extendDeep function based off of the angular.extend function. If you add this to your $scope, you would then be able to call

$scope.meta = $scope.extendDeep(ajaxResponse1.myMeta, ajaxResponse2.defaultMeta);

and get the answer you are looking for.

$scope.extendDeep = function extendDeep(dst) {
  angular.forEach(arguments, function(obj) {
    if (obj !== dst) {
      angular.forEach(obj, function(value, key) {
        if (dst[key] && dst[key].constructor && dst[key].constructor === Object) {
          extendDeep(dst[key], value);
        } else {
          dst[key] = value;
        }     
      });   
    }
  });
  return dst;
};

Note: This function has the side-effect of copying values from later arguments into the earlier arguments. For a simple fix to this side effect, you can change dst[key] = value to dst[key] = angular.copy(value).

like image 186
Ryan O'Neill Avatar answered Nov 08 '22 04:11

Ryan O'Neill


All the answers here are valid for versions of Angular before 1.4

As of Angular 1.4, you can use angular.merge to do exactly that:

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

https://docs.angularjs.org/api/ng/function/angular.merge

like image 38
Julien P Avatar answered Nov 08 '22 03:11

Julien P


function deepExtend(destination, source) {
  for (var property in source) {
    if (source[property] && source[property].constructor &&
     source[property].constructor === Object) {
      destination[property] = destination[property] || {};
      arguments.callee(destination[property], source[property]);
    } else {
      destination[property] = source[property];
    }
  }
  return destination;
}

Plunker

Src: https://gist.github.com/gregdangelo/2343158

like image 44
Stewie Avatar answered Nov 08 '22 03:11

Stewie


Building on Ryan's code, you can shorten the object check and you should also NOT extend functions so you don't override object pointers.

var extendDeep = function extendDeep(dst) {
    angular.forEach(arguments, function(obj) {
        if (obj !== dst) {
            angular.forEach(obj, function(value, key) {
                if (dst[key] && angular.isObject(dst[key])) {
                    extendDeep(dst[key], value);
                } else if(!angular.isFunction(dst[key])) {
                    dst[key] = value;
                }
            });
        }
    });
    return dst;
};
like image 23
amcdnl Avatar answered Nov 08 '22 02:11

amcdnl