2012-11-07 5 views
7

Ich denke, das muss ein häufiges Problem sein, aber scheint nicht die Lösung zu finden. Verwenden von JSON-Konfigurationsdateien zum Erweitern eines jQuery-Objekts, das Objekte und Arrays enthält.Ändern von jQuery erweitern, um Array-Elemente innerhalb von Objekten zu schieben, aber andere Objekte zu erweitern

Für die Objekte und einfache Eigenschaften möchte ich überschreiben (wie extend tut gut).

Für die Arrays können möglicherweise vorhandene Elemente vorhanden sein oder nicht.

Zeit ein Array überschreibt nur die ersten Elemente

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/

Das gibt:

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

Kann ich stattdessen bekommen:

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

während ALSO erlaubt, "erste" und "zweite" Objekte zu aktualisieren?

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

könnte/sollte extend modifiziert werden Array-Elemente zu vergleichen und erweitern oder auf irgendeiner Regel oder Set-Eigenschaftswert wie „name“ hinzufügen?

Vielen Dank für Rat oder Hinweise.

+0

Dies scheint die am nächsten zu sein, die ich gefunden habe, die es tun könnte - http://stackoverflow.com/questions/3748697/jquery-extend-arra y-of-objects –

+0

Die normale Verwendung von '$ .extend' dient zum Zusammenführen von benutzerdefinierten Optionen mit Standardwerten. In diesem Fall empfiehlt es sich in der Regel, dass eine neue Eigenschaft die im ursprünglichen Objekt vollständig ersetzt. Das Anhängen von Array-Eigenschaften passt nicht zu der Art und Weise, wie sie normalerweise verwendet wird. Wofür brauchst du das? – Barmar

+0

@Barmar wahr, das ist ein Anwendungsfall, aber es gibt viele andere ... einschließlich Erweiterung neuer Funktionen/Methoden zu jQuery-Objekt selbst – charlietfl

Antwort

2

habe ich diese Lösung http://jsfiddle.net/PmuwV/2/ von How can I merge properties of two JavaScript objects dynamically? modifiziert auch von JavaScript equivalent of jQuery's extend method

erfordert isDOMNode() ich in einem jquery merge gerade hinzugefügt haben (ja, ich fühle mich zu schmutzig) auf Arrays, in denen werden Duplikate werden müssen gereinigt Post-Merge. Die JQuery-Quelle für Extend macht etwas sehr ähnliches, aber ich fand es besser lesbar.

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; 
} 
+0

aktualisiert um http://jsfiddle.net/PmuwV/5/ um doppelte Array-Objekte mit einer bestimmten passenden Eigenschaft zu verschmelzen –

+0

Benötigt etwas ähnliches, also habe ich Ihr etwas geändert, um Unterstreichungen zu verwenden: http://codepen.io/clouddueling/pen/nFDCH –

+1

Schöne Lösung, aber ich fand 2 Bugs in dem obigen Code gefunden, so fügte ich eine 'Antwort' mit dem aktualisierten Code. – user3708842

2

Es ist ganz einfach mit lodash library

var targetObj = { 
    customerId: "123", 
    orders: [ 
     "item1", "item2" 
    ] 
}; 

var otherObj = { 
    customerName: "John", 
    orders: [ 
     "item3", "item4" 
    ] 
}; 

_.merge(targetObj, otherObj, function (a, b) { 
    if (_.isArray(a)) { 
    return a.concat(b); 
    } 
}); 

Ergebnis ist:

targetObj = { 
    customerId: "123", 
    customerName: "John", 
    orders: [ 
     "item1", "item2", "item3", "item4" 
    ]  
} 
+0

Danke! Das hat perfekt funktioniert! – swrobel

+1

Für jeden, der dies 2016 oder danach liest, scheint es, dass die korrekte lodash-Funktion für das obige Beispiel heute '_.mergeWith()' – AsGoodAsItGets

0

Ich weiß, das ist alt, aber ich fand diesen Beitrag und verwendet Steve Blacks angezeigten Code gefunden, aber ein paar Fehler:

  1. Es gibt ein zusätzliches "}" vor dem "Fortfahren" im isArray-Bereich.
  2. Wenn die Quelle überhaupt nicht das Array haben, wäre es ein Fehler werfen, so fügte ich wie folgt dies in den isArray Abschnitt

    if (!dst[p]) { 
        dst[p] = src[p]; 
        continue; 
    } 
    

So der fertige Code sieht:

function isDOMNode(v) { 
    if (v===null) return false; 
    if (typeof v!=='object') return false; 
    if (!('nodeName' in v)) return false; 
    var nn = v.nodeName; 
    try { 
     v.nodeName = 'is readonly?'; 
    } catch (e) { 
     return true; 
    } 
    if (v.nodeName===nn) return true; 
    v.nodeName = nn; 
    return false; 
} 

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) { 
      if ($.isArray(src[p])) { 
       if (!dst[p]) { 
        dst[p] = src[p]; 
        continue; 
       } 
       $.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;   
      } 

      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; 
} 
0
<html> 
<head> 
<script type="text/javascript" src="./jquery-2.1.3.js"></script> <!-- for json extend/merge --> 
<script type="text/javascript" src="./jQuery.extendext.min.js"></script> <!-- for json extend/merge - with array extend (instead of array overwrite) - https://github.com/mistic100/jQuery.extendext --> 

<script> 
var jsonResult = {}; 
var json1 = 
{ 
    "properties": 
    { 
     "street_address": { "type": "string" }, 
     "city": { "type": "string" }, 
     "state": { "type": "string" } 
    }, 
    "required": ["street_address", "city", "state"] 
}; 
var json2 = 
{ 
    "properties": 
    { 
     "country": { "type": "string" }, 
     "country-dial-code": { "type": "integer" }, 
     "country-short": { "type": "string" } 
    }, 
    "required": ["country", "country-dial-code", "country-short"] 
}; 
$.extendext(true, 'extend', jsonResult, json1, json2); 
console.log(JSON.stringify(jsonResult)); 
/* output -> 
{ "properties": 
    { "street_address":{"type":"string"}, 
     "city":{"type":"string"}, 
     "state":{"type":"string"}, 
     "country":{"type":"string"}, 
     "country-dial-code":{"type":"integer"}, 
     "country-short":{"type":"string"} 
    }, 
    "required":["street_address","city","state","country","country-dial-code","country-short"] 
} 
*/ 
</script> 
</head> 
<body> 
</body> 
</html> 
+0

https://github.com/mistic100/jQuery.extendext –

+0

Schlüssel "F12" ist Ansicht Konsole –

Verwandte Themen