objects de mesclagem profunda com o AngularJS

Normalmente para objects de cópia rasos eu usaria angular.extend()

Aqui está um exemplo disso:

 var object1 = { "key": "abc123def456", "message": { "subject": "Has a Question", "from": "example1@example.com", "to": "example2@example.com" } }; var object2 = { "key": "00700916391" }; console.log(angular.extend({}, object1, object2)); 

Nos daria:

 { "key": "00700916391", "message": { "subject": "Has a Question", "from": "example1@example.com", "to": "example2@example.com" } } 

Mas e se eu quisesse mesclar objects para que as chaves dos pais não fossem escritas por objects-filhos:

 var object1 = { "key": "abc123def456", "message": { "subject": "Has a Question", "from": "example1@example.com", "to": "example2@example.com" } }; 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)); 

Nos daria:

 { "key": "00700916391", "message": { "subject": "Hey what's up?", "from": "example1@example.com", "to": "example2@example.com", "something": "something new" } } 
  • Existe uma function angular que já faz uma mesclagem profunda que eu não conheço?

  • Se não há uma maneira nativa de fazer isso em javascript recursivamente para n níveis de profundidade?

Angular 1.4 ou posterior

Use angular.merge :

Ao contrário de extend() , merge() recursivamente desce em propriedades de objects de origem, executando uma cópia profunda.

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

Versões mais antigas do Angular:

Não há razão para que um algoritmo recursivo simples não funcione 🙂

Assumindo que ambos são o resultado de JSON.stringify ou 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; } 

Aqui está um violino de trabalho

(Nota, matrizes não são tratadas aqui)

Na nova versão do Angularjs, eles adicionaram a function de mesclagem que executará a cópia profunda.

Para as versões mais antigas, criei minha function personalizada copiando o código da function de mesclagem da nova versão do Angularjs. Abaixo está o código para o mesmo,

 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); } 

Espero que isso ajude alguém que está se perguntando por que o angular.merge não está funcionando em versões mais antigas.

polyfill angular.merge para angular <1.4.0

 if (!angular.merge) { angular.merge = (function mergePollyfill() { function setHashKey(obj, h) { if (h) { obj.$$hashKey = h; } else { delete obj.$$hashKey; } } function baseExtend(dst, objs, deep) { var h = dst.$$hashKey; 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.isDate(src)) { dst[key] = new Date(src.valueOf()); } else { if (!angular.isObject(dst[key])) dst[key] = angular.isArray(src) ? [] : {}; baseExtend(dst[key], [src], true); } } else { dst[key] = src; } } } setHashKey(dst, h); return dst; } return function merge(dst) { return baseExtend(dst, [].slice.call(arguments, 1), true); } })(); } 

Aqui está uma solução que leva vários objects mesclar (mais de dois objects):

Aqui está uma function extendDeep baseada na function angular.extend. Se você adicionar isso ao seu $ escopo, você poderá então chamar

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

e obtenha a resposta que você está procurando.

 $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; }; 

Se você estiver usando <1,4

Você pode usar o lodash () do lodash que faz o mesmo que o angular> versão 1.4

Me salvou de escrever novas funções, já que o lodash é bastante popular com pessoas angulares já