I am creating some objects from JSON and I would like to make an empty copy of an object. I would have all the same properties but empty values. What are some good ways of doing this?
Right now I am doing it as follows but would like it to be dynamic from the objects I create from the JSON I receive.
var myObject = { "Address": { "Address1": "", "Address2": "", "Address3": "", "Address4": "", "City": "", "": "", "": "", "Country": "", "Id": -1, "LastModified": "", "PostBackAction": null }, "Id": -1, "Amenities": "", "Directions": "", "LastModified": "", "LocalAttractions": "", "LocalLodging": "", "LocalRestaraunts": "", "Name": "", "Pictures": "", "Prices": "", "Region": 0, "PostBackAction": null };
A possible solution that doesn't work because it copies the values.
var myObject = JSON.parse(JSON.stringify(objectToBeCopied));
You could use a function that creates a copy of the object structure and uses a default value for each data type:
function skeleton(source, isArray) {
var o = Array.isArray(source) ? [] : {};
for (var key in source) {
if (source.hasOwnProperty(key)) {
var t = typeof source[key];
o[key] = t == 'object' ? skeleton(source[key]) : { string: '', number: 0, boolean: false }[t];
}
}
return o;
}
Demo: http://jsfiddle.net/Guffa/ym6ZJ/
var getCopy = function(objectToCopy){
var copy = {};
for(var prop in myObject){
if(typeof(objectToCopy[prop])==="object"){
copy[prop]= getCopy(objectToCopy[prop]);
}
else{
copy[prop]=null;
}
}
return copy;
}
Hope this is what you were looking for:
var myObject = function(){
this.address = {
'Address1': '',
'Address2': '',
'Address3': '',
'Address4': '',
'City': '',
'Country': '',
'Id': 0,
'LastModified': '',
'PostBackAction': null
};
this.Id = -1;
this.Amenities = '';
this.Directions = '';
this.LastModified = '';
this.LocalAttractions = '';
this.LocalLodging = '';
this.LocalRestaraunts = '';
this.Name = '';
this.Pictures = '';
this.Prices = '';
this.Region = 0;
this.PostBackAction = null;
}
// create two new objects
var objectOne = new myObject();
var objectTwo = new myObject();
console.log(objectOne);
//modify the first
objectOne.address.Address1 = 'Lol Street';
console.log(objectOne);
//notice the second one was not changed
console.log(objectTwo);
Related
I have an object like below
{
UserId: "",
BidderId: "",
"1stDomestic.BidderId": "",
"1stDomestic.UserId": "234",
"1stEmployee.CreatedDate": "",
"1stIndependent.UpdatedDate": "",
"1stIndependent.CreateDate": ""
}
The requirement is such that I need to group the dotted object keys and create the output as below
{
UserId: "",
BidderId: "",
1stDomestic: [
{
BidderId="",
UserId="234"
}
],
1stEmployee: [
{
CreatedDate=""
}
],
1stIndependent: [
{
UpdatedDate="",
CreatedDate=""
}
],
lstDomestic.BidderId = "",
1stDomestic.UserId="234",
1stEmployee.CreatedDate="",
1stIndependent.UpdatedDate=""
1stIndependent.CreateDate=""
}
I have tried to achieve this using couple of approaches.
Here requestedData is the object
Approach 1
for (let prop in requestedData) {
if (prop.indexOf(".") > -1) {
mainKey[prop.split(".").pop()] = requestedData[prop];
requestedData[prop.substr(0, prop.indexOf("."))] = [mainKey];
}
}
console.log(requestedData)
The above approach gives me the structure, but the array data reflects the same for all.
1stDomestic: [
{
BidderId="",
UserId="234",
CreatedDate="",
UpdatedDate=""
}
],
1stEmployee: [
{
BidderId="",
UserId="234",
CreatedDate="",
UpdatedDate=""
}
],
1stIndependent: [
{
BidderId="",
UserId="234",
CreatedDate="",
UpdatedDate=""
}
]
Approach 2
for (let prop in requestedData) {
if (prop.indexOf(".") > -1) {
arr.push({
newProp: prop.substr(0, prop.indexOf(".")), //-->1
mainKey: prop.split(".").pop(), // --> 2
value: requestedData[prop] // -->3
});
}
}
console.log(Object.assign(requestedData, groupData(arr));
groupData(arrVal) {
let key = "newProp";
return resData.reduce((previous, current) => {
previous[current[key]] && previous[current[key]].length != 0
? previous[current[key]].push(current)
: (previous[current[key]] = new Array(current));
return previous;
}, {});
}
The above approach groups the data based on the keys, but then it creates and individual arrays of object with properties as in 1,2 and 3
I expect this to be the way as mentioned above.
I am kind of now in a fix and trying to figure that out.
I am new to this forum, asking question, please bear if I somehow made this question too lengthy and intuitive.
Help would be appreciated
You can first create an object of nested objects based on the keys using reduce and then merge your original object with the nested object to get your final result:
const data = {
UserId: "",
BidderId: "",
"1stDomestic.BidderId": "",
"1stDomestic.UserId": "234",
"1stEmployee.CreatedDate": "",
"1stIndependent.UpdatedDate": "",
"1stIndependent.CreateDate": ""
};
const nested = Object.entries(data)
.filter(([k, v]) => k.includes('.'))
.reduce((acc, [k, v]) => {
const [parent, child] = k.split('.');
acc[parent] = acc[parent] || [{}];
acc[parent][0][child] = v;
return acc;
}, {});
const result = { ...data, ...nested};
console.log(result);
You can use below solution.
var requestedData = {
UserId: "",
BidderId: "",
"lstDomestic.BidderId" : "",
"lstDomestic.UserId":"234",
"lstEmployee.CreatedDate":"",
"lstIndependent.UpdatedDate":"",
"lstIndependent.CreateDate":""
}
var newData = [];
var previousKey = "";
for (let prop in requestedData) {
if (prop.indexOf(".") > -1) {
if(previousKey != prop.substr(0, prop.indexOf(".")))
{
ainKey = [];
}
previousKey = prop.substr(0, prop.indexOf("."))
mainKey[prop.split(".").pop()] = requestedData[prop];
newData[prop.substr(0, prop.indexOf("."))] = [mainKey];
}
}
console.log(newData)
you can try live working demo.
https://jsfiddle.net/cakp8z6n/4/
If you call your original object obj, this should work:
Object.keys(obj).forEach(key => {
if (key.includes('.')) {
const [base, suffix] = key.split('.');
obj[base] = obj[base] || [{}];
obj[base][0][suffix] = obj[key];
}
});
console.log(obj);
Or, if you don't want to modify the original object, but make a modified copy instead:
const obj2 = {};
Object.keys(obj).forEach(key => {
obj2[key] = obj[key];
if (key.includes('.')) {
const [base, suffix] = key.split('.');
obj2[base] = obj2[base] || [{}];
obj2[base][0][suffix] = obj[key];
}
});
let orgObj={
UserId: "",
BidderId: "",
"lstDomestic.BidderId": "",//difference 1st and Ist
"1stDomestic.UserId": "234",//difference 1st and Ist
"1stEmployee.CreatedDate": "",
"1stIndependent.UpdatedDate": "",
"1stIndependent.CreateDate": ""
};
let complexKeys = Object.keys(orgObj).filter(key=>{return key.match(/.+\..+/)})
So complexKeys now ["lstDomestic.BidderId", "1stDomestic.UserId", "1stEmployee.CreatedDate", "1stIndependent.UpdatedDate", "1stIndependent.CreateDate"]
complexKeys.forEach(eachCompleKey=>{debugger;
let firstPart= eachCompleKey.match(/^(\w+)\./)[1];
let lastPart= eachCompleKey.match(/\.(\w+)$/)[1];
if(orgObj[firstPart]==undefined){debugger;
orgObj[firstPart]=[{}];
}
orgObj[firstPart][0][lastPart]=orgObj[eachCompleKey]
})
console.log(orgObj)
Output
{
"UserId": "",
"BidderId": "",
"lstDomestic.BidderId": "",
"1stDomestic.UserId": "234",
"1stEmployee.CreatedDate": "",
"1stIndependent.UpdatedDate": "",
"1stIndependent.CreateDate": "",
"lstDomestic": [
{
"BidderId": ""
}
],
"1stDomestic": [
{
"UserId": "234"
}
],
"1stEmployee": [
{
"CreatedDate": ""
}
],
"1stIndependent": [
{
"UpdatedDate": "",
"CreateDate": ""
}
]
}
You can try something like below.
let obj = {
UserId: "",
BidderId: "",
"lstDomestic.BidderId": "",
"1stDomestic.UserId": "234",
"1stEmployee.CreatedDate": "",
"1stIndependent.UpdatedDate": "",
"1stIndependent.CreateDate": ""
};
const res = Object.keys(obj).reduce((acc, mainKey) => {
let [key1, key2] = mainKey.split(".");
if (key2 && acc[key1]) {
acc[key1][0] = { ...acc[key1][0],
...{
[key2]: obj[mainKey]
}
}
} else if (key2) {
acc[key1] = [{
[key2]: obj[mainKey]
}];
} else {
acc[key1] = obj[key1];
}
return acc;
}, {})
const finalResult = { ...obj,
...res
};
console.log(finalResult)
So this code will do it, but I'm confused why you want it in this format. It seems like it would make more sense to have 1stDomestic, 1stEmployee, and 1stIndependent be their own objects rather than single element arrays. It just requires you to do more work later to access the data!
var requestedData = {
UserId: "",
BidderId: "",
"lstDomestic.BidderId" : "",
"lstDomestic.UserId":"234",
"lstEmployee.CreatedDate":"",
"lstIndependent.UpdatedDate":"",
"lstIndependent.CreateDate":""
}
let output = {};
for (let prop in requestedData) {
// Check to see if this is a "blah.thing" property
if (prop.includes(".")) {
let props = prop.split(".");
// Check to see if we've added the array already
if (output[props[0]])
output[props[0]][0][props[1]] = requestedData[prop];
else
// ES 2015 baby!
output[props[0]] = [{[props[1]]: requestedData[prop]}]
}
// If it's not then just add it normally
else
output[prop] = requestedData[prop];
}
console.log(output);
Here is a module let say,
var UI = UI || {};
UI.Old = {
v1: "",
v2: "",
v3: [],
v4: 0,
v5: "",
v6: "",
v7: "xxxx",
v8: "",
v9: "",
v10: "",
init: function(options) {
this.v1 = options.v1;
this.v10 ... and so on
this.showLatestTime(new Date().getSeconds())
},
showLatestTime: function(time) {
document.getElementById('results').innerHTML = time;
}
};
Is there any way I could hide these variables and make them more readable ?
you can have a object with all options and use an extend function
(function (root) {
root.extend = function (obj) {
var source, prop;
for (var i = 1, length = arguments.length; i < length; i++) {
source = arguments[i];
for (prop in source) {
if (hasOwnProperty.call(source, prop)) {
obj[prop] = source[prop];
}
}
}
return obj;
};
})(window);
var UI = UI || {};
UI.Old = {
settings:{
v1: "",
v2: "",
v3: [],
v4: 0,
v5: "",
v6: "",
v7: "xxxx",
v8: "",
v9: "",
v10: ""
},
init: function(options) {
this.settings = extend(this.settings,options);
// this.showLatestTime(new Date().getSeconds())
},
showLatestTime: function(time) {
document.getElementById('results').innerHTML = time;
},
showSettings:function(){
console.log(this.settings)
}
};
UI.Old.init({
v1:"test1",v2:"test2",v3:[1,2,3],v10:"123"
});
UI.Old.showSettings();
This question already has answers here:
How do I correctly clone a JavaScript object?
(81 answers)
Closed 6 years ago.
I have an object like this:
{"question": "", "options" : [{"subject": "", "teacher": "", "answer": [] }
}
I want to copy data from this object into this:
{"question": "", "options" : [{"subject": "", "teacher": "", "new":" " }
}
I want to add the field "new" instead of "answer"
Deep cloning can be achieved like this: var b = JSON.parse(JSON.stringify(a));
The requested manipulation would be
var a = {"question": "", "options" : [{"subject": "", "teacher": "","answer": [] }}
var b = JSON.parse(JSON.stringify(a))
delete b.options[0].answer
b.options[0].new = 'your content'
For the sake of another answer... (though I rather liked the first one from #lipp)
Here is a function that deep clones your object and swithches the answer key for the new key.
Problem this will substitue any key answer wherever it may find it. So that if you do this:
clone({"question": "", "answer" : [{"subject": "", "teacher": "", "answer": [] ] } })
Result is
{"question": "", "new" : " " }
var toClone = {"question": "", "options" : [{"subject": "", "teacher": "", "answer": [] ] } };
function clone(original){
var copy;
if (original instanceof Array) {
copy = [];
for (var i = 0, limit = original.length; i < limit; ++i) {
copy[i] = clone(original[i]);
}
} else if (original instanceof Object) {
copy = {};
for (var key in original) {
if( key === "answer" ){
copy["new"] = " ";
} else
copy[copiedKey ] = clone(original[key]);
}
} else
copy = original;
return copy;
}
I am trying to merge my objects and get a result like below
{
"sports": {
"basketball": "kobe",
"swimming": {
},
"football": "ronaldo",
"running": "",
"highJump": ""
},
"calendar": ["21", "25", "30"]
}
Somewhere I am doing wrong in my logic can you help me out
but if I alternate my sportA and sportsB value I am getting expected
results...not sure what problem in my current scenario
providing my code below.
fiddle
https://jsfiddle.net/tjLk0frq/3/
var sportsA ={
"sports": {
"basketball": "kobe",
"football": "ronaldo"
}
};
var sportsB ={
"sports": {
"basketball": "",
"swimming": {
},
"football": "",
"running": "",
"highJump": ""
},
"calendar": ["21", "25", "30"]
};
function merge(sportsA, sportsB) {
for( var p in sportsB )
if( sportsA.hasOwnProperty(p) )
sportsA[p] = typeof sportsB[p] === 'object' ? merge(sportsA[p], sportsB[p]) : sportsB[p];
return sportsA;
}
merge(sportsA, sportsB );
console.log("unexpected result" + sportsA );
console.log( sportsA );
//expected
/*
{
"sports": {
"basketball": "kobe",
"swimming": {
},
"football": "ronaldo",
"running": "",
"highJump": ""
},
"calendar": ["21", "25", "30"]
}
*/
You can use jQuery's extend method, with deep merge enabled, to do this:
var output = $.extend(true, sportsB, sportsA)
outputs:
{
"sports": {
"basketball": "kobe",
"swimming": {},
"football": "ronaldo",
"running": "",
"highJump": ""
},
"calendar": ["21", "25", "30"]
}
You have mistake when you check sportsA.hasOwnProperty(p) in your case you only update properties that are in sportsA, but not add new from sportsB.
Also if sportsB[p] has falsy value you don't want to update it for that I've used (sportsB[p] || sportsA[p]).
Check this code.
var sportsA ={
"sports": {
"basketball": "kobe",
"football": "ronaldo"
}
};
var sportsB ={
"sports": {
"basketball": "",
"swimming": {
},
"football": "",
"running": "",
"highJump": ""
},
"calendar": ["21", "25", "30"]
};
function merge(sportsA, sportsB) {
for( var p in sportsB )
if( sportsA.hasOwnProperty(p) ) {
sportsA[p] = typeof sportsB[p] === 'object' ? merge(sportsA[p], sportsB[p]) : (sportsB[p] || sportsA[p]);
} else {
sportsA[p] = sportsB[p];
}
return sportsA;
}
merge(sportsA, sportsB );
console.log("unexpected result" + sportsA );
console.log( sportsA );
Here you go (pure JS):
function merge(obj1, obj2) {
var result = {};
for (var prop in obj1) {
if (typeof obj1[prop] === "object" && typeof obj2[prop] === "object")
result[prop] = merge(obj1[prop], obj2[prop]);
else
result[prop] = obj1[prop];
}
for (var prop in obj2) {
result[prop] = (result[prop]? result[prop]: obj2[prop]);
}
return result;
}
console.log(merge(sportsA, sportsB));
This returns a new object, rather than modify an existing one, however.
In the first for..in loop, we check if we need to recurse first, otherwise set the property of result.
In the second for..in loop, we check if the property was already defined or if it's empty, and set the property accordingly.
Output:
{
"sports": {
"basketball": "kobe",
"football": "ronaldo",
"swimming": {},
"running": "",
"highJump": ""
},
"calendar": ["21", "25", "30"]
}
JSFiddle demo
The logic is breaking because when you only loop the property keys in one of the objects, you won't see the property keys that only exist in the other object.
You can get the root level keys of an object using Object.keys() which returns an array of the property names. Then you can merge the 2 sets of keys at same level and know all the final output properties needed
Then iterate those to get final results
I have having trouble figuring out how I can limit my output. I have to compare values of each attribute within an object, however I only want 1 output per ID.
Any thoughts?
//example JSON
var obj1 = {
"Summary" :
[
{
"ID" : "1234",
"Name" : "John",
"Status" : "Green",
},
{
"ID" : "5678",
"Name" : "Mike",
"Status" : "Green",
},
{
"ID" : "9012",
"Name" : "Tom",
"Status" : "Red",
}
]
};
//my code
var attributesvalues = ["Mike", "Green", "Red"];
var sg1 = [];
var k;
var l;
//push name of each attribute value to a new array
//one example
sg1.push(attributesvalues[0]);
//go through each ID, if name value exist, push the #1, if not, push nothing
for (k = 0; k < obj1.Summary.length; k++) {
for (l in obj1.Summary[k]) {
if (sg1[0] == obj1.Summary[k][l]){
sg1.push("1");
}
else{
sg1.push("");
}
}
}
output should look like this - I only want 4 values, name + a 1 or "" for each ID(3)
sg1 = ["Mike", "", "1", ""]
sg2 = ["Green", "1", "1", ""]
instead I am getting this - the name + a 1 or "" for each attribute.
sg1 = ["Mike", "", "", "", "", "1", "", "", "", ""]
sg2 = ["Green", "", "", "1", "", "", "1", "", "", ""]
Any additional pointers or tips you could provide would be much appreciated. I am still trying to get the hang of JS.
You don't know if you have a match or not until you finish the entire for-in loop.
var found;
for (k = 0; k < obj1.Summary.length; k++) {
found = "";
for (l in obj1.Summary) {
if (obj1.Summary[i][l] == sg1[0]) {
found = "1";
break;
}
}
sg1.push(found);
}