Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying jQuery extend to push array items within objects but extend other objects

I'm thinking this must be a common problem but can't seem to find the solution. Using JSON config files to extend a jQuery object that contains objects and arrays.

For the objects and simple properties, I want to overwrite (as extend does nicely).

For the arrays there may or may not be existing items.

Currently an array just overwrites the first elements

var sourceObj = {propterty:"change Me",anArray:[{name:"first"},{name:"second"}]},
    configJSON = '{"propterty":"New Val","anArray":[{"name":"third"}]}',
    configObj = JSON.parse(configJSON);

$.extend(true,sourceObj,configObj);

http://jsfiddle.net/PmuwV/

This returns:

{propterty:"New Val" , anArray:[{name:"third"},{name:"second"}}

Can I instead get:

{propterty:"New Val",anArray:[{name:"first"},{name:"second"},{name:"third"}]}

while ALSO allowing for updating "first" and "second" objects?

"anArray":[{"name":"second","newProp":"add newProp to second"}]

Could/should extend be modified to compare array items and extend or add based on some rule or set property value such as "name"?

Thanks for any advice or pointers.

like image 789
Steve Black Avatar asked Nov 07 '12 23:11

Steve Black


1 Answers

I used this solution http://jsfiddle.net/PmuwV/2/ modified from How can I merge properties of two JavaScript objects dynamically? also from JavaScript equivalent of jQuery's extend method

requires isDOMNode() I just added in a jquery merge (yes I feel dirty too) on arrays in which duplicates will need to be cleaned up post merge. The Jquery source for extend does something very similar but i found this to be more readable.

function mergeRecursive() {
  // _mergeRecursive does the actual job with two arguments.
  var _mergeRecursive = function (dst, src) {
    if ( isDOMNode(src) || typeof src!=='object' || src===null) {
      return dst; 
    }

    for ( var p in src ) {

//my added bit here - [SB]
      if ($.isArray(src[p])){
          $.merge(dst[p],src[p]);
          var dupes = {},
               singles = [];
          $.each(  dst[p], function(i, el) {
             if ((dupes[el.name] > -1) &&  (el.name)) {
                 $.extend(singles[dupes[el.name]],el);
             }else{
                  if (el.name ){
                     dupes[el.name] = i;
                  }
                 singles.push(el);
             }
         });
         dst[p] = singles;
         }
         continue;        
      }
//the rest is original - [SB]

      if( !src.hasOwnProperty(p) ) continue;
      if ( src[p]===undefined ) continue;
      if ( typeof src[p]!=='object' || src[p]===null) {
        dst[p] = src[p];
      } else if ( typeof dst[p]!=='object' || dst[p]===null ) {
        dst[p] = _mergeRecursive(src[p].constructor===Array ? [] : {}, src[p]); 
      } else {              
        _mergeRecursive(dst[p], src[p]);
      }
    }
    return dst;
  }

  // Loop through arguments and merge them into the first argument. 
  var out = arguments[0];
  if ( typeof out!=='object' || out===null) return out;
  for ( var i=1, il=arguments.length; i<il; i++ ) {
    _mergeRecursive(out, arguments[i]);
  }
  return out;
}
like image 85
Steve Black Avatar answered Nov 02 '22 17:11

Steve Black