I am new using js , I had function to store object in array to Angular model,
for example :
function getSpec(){
debugger
var i;
for(i=0;i<main.specifications.length;i++){
main.newProduct.Specification= ("{\""+main.specifications[i].key+"\":\""+main.specifications[i].value+"\"}");
}
}
main.newProduct.Specification is a model, and I want to store key and value according to array length.
and I want to store to db like: {"Ram":"1GB","Color":"BLACK"}
what should i do?
Change the getSpec() as follows:
function getSpec(){
debugger
var i;
main.newProduct.Specification = main.newProduct.Specification || {}; // This is optional, and is just a fallback
for(i = 0; i < main.specifications.length; i++) {
main.newProduct.Specification[main.specifications[i].key] = main.specifications[i].value;
}
}
The above initializes main.newProduct.Specification with an empty object if it is not already initialized and appends all the properties to it.
Update:
The above can also be reduced to this:
function getSpec() {
main.newProduct.Specification = main.specifications.reduce(function(obj, item) {
obj[item.key] = item.value;
return obj;
}, {});
}
If main.newProduct.Specification is object then you can create key value pair using main.newProduct.Specification[main.specifications[i].key] = main.specifications[i].value;
function getSpec(){
debugger
var i;
for(i=0;i<main.specifications.length;i++){
var temp = {};
temp[main.specifications[i].key]=main.specifications[i].value;
main.newProduct.Specification.push(temp);
}
}
Try this solution using ES6 for...of loop :
let mainObj = {
"specifications" : [
{ "key":"Ram", "value":"1GB" },
{ "key":"Color", "value":"BLACK" }
]
};
mainObj.newProduct = {
"specifications" : {}
}
for (let i of mainObj.specifications) {
mainObj.newProduct.specifications[i.key] = i.value;
}
console.log(mainObj.newProduct.specifications);
Related
I was wondering if it is possible to dynamically generate an object with an array of strings in dot notation. I would like to dynamically build a JSON object from a CSV file. The goal is to build the CSV as JSON, then filter the properties and make a new JSON object.
So I would like to pass in something like this..
var obj = {};
var keyArray = ['meta', 'logos', 'warranty', 'specs', 'specs.engine', 'specs.engine.hp', 'specs.engine.rpm', 'specs.engine.manufacturer'];
The end result would be something like this...
obj = {
meta: {
},
logos: {
},
specs: {
engine: {
hp: {
}
}
}
}
Here is the main function
function addObjectsByKey(obj, keyArray) {
for (var key in keyArray) {
// If keyword is not in object notation
if (!(keyArray[key].match(/\./))) {
// If the object property is not set, set it
if (!(obj[keyArray[key]])) {
obj[keyArray[key]] = {};
}
} else {
// Split array element (in dot notation) into an array of strings
// These strings will be object properties
var pathAsArray = keyArray[key].split('.');
var path = null;
for (var k in pathAsArray) {
if (path == null) {
obj[pathAsArray[k]] = {};
path = pathAsArray[k];
} else {
obj[path][pathAsArray[k]] = {};
path += '.' + pathAsArray[k];
}
}
// throw Error('end');
}
}
// return obj;
}
You can use forEach loop and inside you can split each element on . and then use reduce method to build nested object.
var keyArray = ['meta', 'logos', 'warranty', 'specs', 'specs.engine', 'specs.engine.hp', 'specs.engine.rpm', 'specs.engine.manufacturer'];
const result = {}
keyArray.forEach(key => {
// Loop array of keys
// Split each key with . and use reduce on that
// In each iteration of reduce return r[e] which is going to be value if property exists
// or new object if it doesn't
// This way you can go to any object depth as long as keys match existing keys in object.
key.split('.').reduce((r, e) => r[e] = (r[e] || {}), result)
})
console.log(result)
Here is another approach using for loops that will return the same result.
var keyArray = ['meta', 'logos', 'warranty', 'specs', 'specs.engine', 'specs.engine.hp', 'specs.engine.rpm', 'specs.engine.manufacturer' ];
const result = {}
for(var i = 0; i < keyArray.length; i++) {
const keys = keyArray[i].split('.');
let ref = result;
for(var j = 0; j < keys.length; j++) {
const key = keys[j];
if(!ref[key]) ref[key] = {}
ref = ref[key]
}
}
console.log(result)
You can use the function reduce along with a nested forEach to build the path.
The first reduce will accumulate the nested operation.
The nested forEach will build the object and its children according to the current path separated by dots.
let keyArray = ['meta', 'logos', 'warranty', 'specs', 'specs.engine', 'specs.engine.hp', 'specs.engine.rpm', 'specs.engine.manufacturer'],
newObj = keyArray.reduce((accum, path) => {
let previous = accum;
path.split('.').forEach(key => {
if (previous[key]) previous = previous[key];
else previous = previous[key] = {};
});
return accum;
}, {});
console.log(newObj);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have this array:
["userconfig", "general", "name"]
and I would like it to look like this
data_structure["userconfig"]["general"]["name"]
I have tried this function:
inputID = "userconfig-general-name"
function GetDataByID(inputID){
var position = '';
for (var i = 0; i < inputID.length; i++) {
var hirarchy = inputID[i].split('-');
for (var index = 0; index < hirarchy.length; index++) {
position += '["'+ hirarchy[index] +'"]';
}
}
return data_structure[position];
}
while hirarchy is the array. I get the [position] as a string which is not working well.
how can I make a js function which builds the object path dynamically by an array?
var arr = ["userconfig", "general", "name"];
var dataStructure = arr.reduceRight(function (value, key) {
var obj = {};
obj[key] = value;
return obj;
}, 'myVal');
Ends up as:
{ userconfig : { general : { name : 'myVal' } } }
Note that you may need a polyfill for the reduceRight method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight
The below function will take an object to modify and an array filled with the properties needed:
function objPath(obj,path){
path.forEach(function(item){
obj[item] = {};
obj = obj[item];
});
}
var myobj = {};
objPath(myobj,["test","test2","test3"]);
console.log(myobj);
//outputs
Object {test: Object}
test: Object
test2: Object
test3: Object
The function loops over the array creating the new object property as a new object. It then puts a reference to the new object into obj so that the next property on the new object can be made.
JSFiddle
Recursive function
var array = ["userconfig", "general", "name"];
function toAssociative(array) {
var index = array.shift();
var next = null;
if (array.length > 0) {
next = toAssociative(array);
}
var result = new Array();
result[index] = next;
return result;
}
I am trying to create a javascript object like
var allUserExpiry={};
allUserExpiry[aData.userId][aData.courseId][aData.uscId] = aData;
But I am getting an error like allUserExpiry[aData.userId] undefined.
Is there a way, whereby I can set multi-level JS-Object keys? or is it important that I should go by doing allUserExpiry[aData.userId]={}, then allUserExpiry[aData.userId][aData.courseId]={} ?
Please let me know if there are any utility functions available for the same.
No, there is no way to set "multilevel keys". You need to initialize each object before trying to add properties to it.
var allUserExpiry = {};
allUserExpiry[aData.userId] = {}
allUserExpiry[aData.userId][aData.courseId] = {}
allUserExpiry[aData.userId][aData.courseId][aData.uscId] = aData;
Using Computed property names from ES6, it is possible to do:
var allUserExpiry = {
[aData.userId] = {
[aData.courseId]: {
[aData.uscId]: aData
}
}
};
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names
Simply use loadash,
let object = {};
let property = "a.b.c";
let value = 1;
_.set(object, property, value); // sets property based on path
let value = _.get(object, property, default); // gets property based on path
Or you can do it:
function setByPath(obj, path, value) {
var parts = path.split('.');
var o = obj;
if (parts.length > 1) {
for (var i = 0; i < parts.length - 1; i++) {
if (!o[parts[i]])
o[parts[i]] = {};
o = o[parts[i]];
}
}
o[parts[parts.length - 1]] = value;
}
And use:
setByPath(obj, 'path.path2.path', someValue);
This approach has many weak places, but for fun... :)
Why not just do this?
var allUserExpiry={};
allUserExpiry[aData.userId] = {aData.courseId: {aData.uscId: aData}};
I have a pretty hacky but short way of doing it in IE9+ as well as real browsers.
Given var path = 'aaa.bbb.ccc.ddd.eee'; where path is what your intending to make into an object and var result = {}; will will create the object {aaa: {bbb: {ccc: {ddd: {eee: {}}}}}
result = {}
path.split('.').reduce(function(prev, e) {
var newObj = {};
prev[e] = newObj;
return newObj;
}, result);
will store the object in result.
How it works:
split('.') converts the input into ['aaa', 'bbb', 'ccc', 'ddd', 'eee']
reduce(function (...) {...}, result) runs through the array created by split, and for each entry will pass along a returned value to the next one. In our case we pass the new object through after adding the new object to the old one. This creates a chain of objects. reduce returns the last object you return inside of it, so we have to defined result beforehand.
This relies on using references so it won't be immediately clear how it works if you're expecting your code to be maintained by anyone else and should probably be avoided to be honest, but it works at least.
You can also use the following to create the initial structure:
var x = function(obj, keys) {
if (!obj) return;
var i, t;
for (i = 0; i < keys.length; i++) {
if (!t) {
t = obj[keys[i]] = {};
} else {
t[keys[i]] = {};
t = t[keys[i]];
}
}
};
var a = {};
x(a, ['A', 'B', 'C', 'D', 'E', 'F']);
Another approach without strings or array as argument.
function fillObject() {
var o = arguments[0];
for(var i = 1; i < arguments.length-1; i++) {
if(!o.hasOwnProperty(arguments[i])) {
o[arguments[i]] = {};
}
if(i < arguments.length-2) {
o = o[arguments[i]];
}else {
o[arguments[i]] = arguments[i+1]
}
}
}
var myObj = {"foo":{}};
fillObject(myObj,"back","to","the","future",2);
console.log(JSON.stringify(myObj));
// {"foo":{},"back":{"to":{"the":{"future":2}}}}
But I wouldn't use it :-) It's just for fun.
Because I don't like too much intelligent algorithm. (If it was in this category)
Using lodash you can do this easily (node exists and empty check for that node)..
var lodash = require('lodash-contrib');
function invalidateRequest(obj, param) {
var valid = true;
param.forEach(function(val) {
if(!lodash.hasPath(obj, val)) {
valid = false;
} else {
if(lodash.getPath(obj, val) == null || lodash.getPath(obj, val) == undefined || lodash.getPath(obj, val) == '') {
valid = false;
}
}
});
return valid;
}
Usage:
leaveDetails = {
"startDay": 1414998000000,
"endDay": 1415084400000,
"test": { "test1" : 1234 }
};
var validate;
validate = invalidateRequest(leaveDetails, ['startDay', 'endDay', 'test.test1']);
it will return boolean.
Another solution using reduce function (thanks Brian K).
Here we created a get/set to general proposes. The first function return the value in any level. The key is splited considering the separator. the function return the value refered from last index in the key's array
The second function will set the new value considering the last index of the splited key
the code:
function getObjectMultiLevelValue(_array,key,separator){
key = key.split(separator || '.');
var _value = JSON.parse(JSON.stringify(_array));
for(var ki in key){
_value = _value[key[ki]];
}
return _value;
}
function setObjectMultiLevelValue(_array,key,value,forcemode,separator){
key.split(separator || '.').reduce(function(prev, currKey, currIndex,keysArr) {
var newObj = {};
if(prev[currKey] && !forcemode){
newObj = prev[currKey];
}
if(keysArr[keysArr.length-1] == currKey){
newObj = value;
prev[currKey] = newObj;
}
prev[currKey] = newObj;
return newObj;
}, _array);
return _array;
}
//testing the function
//creating an array
var _someArray = {a:'a',b:'b',c:{c1:'c1',c2:{c21:'nothing here...'}}};
//a multilevel key to test
var _key = 'a,a1,a21';
//any value
var _value = 'new foo in a21 key forcing replace old path';
//here the new value will be inserted even if the path exists (forcemode=true). Using comma separator
setObjectMultiLevelValue(_someArray,_key,_value,true,',');
console.log('_someArray:');
console.log(JSON.stringify(_someArray));
//inserting another value in another key... using default separator
_key = 'c.c2.c21';
_value = 'new foo in c21 key';
setObjectMultiLevelValue(_someArray,_key,_value);
console.log('_someArray:');
console.log(JSON.stringify(_someArray));
//recovering the saved value with different separators
_key = 'a,a1,a21';
console.log(getObjectMultiLevelValue(_someArray,_key,','));
_key = 'c.c2.c21';
console.log(getObjectMultiLevelValue(_someArray,_key));
Let assume our object is
const data = {
//some other data
userInfo: {},
};
First, define a new property of that object
data.userInfo.vehicle = {};
then simply
data.userInfo.vehicle.vehicleType = state.userInfo.vehicleType;
Say I have an object and I want to set a variable deep nested inside this object, but the var does not yet exist. What's the best way to do this? If I for example have a string that shows where the variable to be updated should be, like below.
var myObject = {};
var location = "myObject.test.myVar";
var value = "My value!";
setValue(location, value, myObject);
I want this to result in:
myObject = {
test: {
myVar: "My value!"
}
};
And location can be much deeper than that.
Any help is appreciated!
Thanks!
Andreas
This function will do what you want.
Note that it changes the object by reference.
Note it ignores the first name as it's the object itself.
function setValue(location, value, object)
{
var path = location.split(".");
var current = object;
for (var i = 1; i < path.length; i++)
{
if ((i + 1) == path.length)
current[path[i]] = value;
else
{
current[path[i]] = {};
current = current[path[i]];
}
}
}
var myObject = {};
var location = "test.my.deep.hidden.nested.myVar";
var otherLoc = "test.my.deep.secret.var";
var value = "My value!";
function setValue(location, value, obj){
var i, prev = obj, curr;
location = location.split(".");
for(i = 0; i < location.length - 1; ++i){
curr = prev[location[i]];
if("object" !== typeof curr){
prev[location[i]] = {}
curr = prev[location[i]];
}
prev = curr;
}
curr[location[i]] = value;
}
setValue(location, value, myObject);
setValue(otherLoc, 42, myObject);
console.log(JSON.stringify(myObject));
Result:
{
"test": {
"my": {
"deep": {
"hidden": {
"nested": {
"myVar": "My value!"
}
},
"secret": {
"var":42
}
}
}
}
}
Note that you might want to add some features, like checking whether the location is actually valid ("this.is..invalid").
You can simply access object inside another object by Dot(.)
So in your case, you are specifying the expression in quotes. You can try this out
var location = myObject.test.myVar; //Without quotes
and similarly if you have more nested objects.
I have 3 json arrays, each with information listed in the same format:
Array:
ID:
NAME:
DATA:
ID:
NAME:
DATA:
etc...
My goal is to combine all 3 arrays into one array, and sort and display by NAME by passing the 3 arrays into a function.
The function I've tried is:
Javascript Call:
// to save time I'm just passing the name of the array, I've tried passing
// the full array name as json[0]['DATA'][array_1][0]['NAME'] as well.
combineNames(['array_1','array_2']);
FUNCTION:
function combineNames(names) {
var allNames = []
for (i=0;i<names.length;i++) {
for (j=0;j<json[0]['DATA'][names[i]].length;j++) {
allNames.push(json[0]['DATA'][names[i]][j]['NAME']);
}
}
return allNames.sort();
}
The above gives me the error that NAME is null or undefined.
I've also tried using the array.concat function which works when I hard code it:
var names = [];
var allNames = [];
var names = names.concat(json[0]['DATA']['array_1'],json[0]['DATA']['array_2']);
for (i=0;i<names.length;i++) {
allNames.push(names[i]['NAME']);
}
return allNames.sort();
But I can't figure out how to pass in the arrays into the function (and if possible I would like to just pass in the array name part instead of the whole json[0]['DATA']['array_name'] like I was trying to do in the first function...
you can combine JSON easily with jQuery :
var x ={ a:1, b:2 };
var y ={ a:2, c:3 };
var z ={ b:3, d:4 };
$.extend(x, y, z);
console.dir(x); // now 'x' is all of them combined
If you've got 3 arrays like this:
[{ "id":1, "name":"Bob", "data":1},{ "id":2, "name":"Fred", "data":2 }]
Simply do:
function combine() {
var ar = [];
return ar.concat.apply(ar, arguments).sort(function (a, b) {
var aName = a.NAME;
var bName = b.NAME;
if (aName < bName) {
return -1;
} else if (aName == bName) {
return 0;
} else {
return 1;
};
});
};
Then call it like:
var jointArrays = combine(array1, array2, array3, ...);
However, if your JSON looks like this:
json[0]['DATA'][array_1]
json[0]['DATA'][array_2]
json[0]['DATA'][array_3]
You can simply define combine() as follows, which will be more convenient:
function combine(arrays) {
var ar = [];
return ar.concat.apply(ar, arrays).sort(function (a, b) {
var aName = a.NAME;
var bName = b.NAME;
if (aName < bName) {
return -1;
} else if (aName == bName) {
return 0;
} else {
return 1;
};
});
};
Then call it like:
var jointArrays = combine(json[0].DATA);
If you're wanting an array of just the names, rather than the objects, use the following:
function combine(arrays) {
var ar = [],
ret = [];
ar = ar.concat.apply(ar, arrays);
for (var i=0;i<ar.length;i++) {
ret.push(ar.NAME);
};
return ret.sort();
};
Javascript is case sensitive; make sure it's DATA and not data, and NAME and not name.
Now for a little bit of housekeeping.
In your example, both of your counter variables are being declared as "implied globals", because you're not prefixing them with the var statement (and implied globals are bad). You should use:
for (var i=0;i<something.length;i++) {
//
};
Instead of neglecting the var.
Also, "{}" creates an object. "[]" creates an array. Javascript does not support associative array's; e.g array's with keys that are anything except a number. What you're JSON is returning is an array of objects
"Square notation" and "dot notation" are interchangeable. object["one"] is equivalent to object.one
Square notation is generally used when the key is stored as a variable, or when you're accessing an array.
var key = "one";
object[key]
Hope this helps.
You're redeclaring the allNames variable, emptying it.
Try this:
function combineNames(names) {
var allNames = [];
var data = json[0]['DATA'];
for (arrnames in data) {
for (j=0;j<data[arrnames].length;j++) {
if ('NAME' in data[arrnames]){
allNames.push(data[arrnames]['NAME']);
}
}
}
return allNames.sort();
}
function allNames(names) {
var allNames = [];
for (var i=0;i<names.length;i++) {
for (var j=0;j<json[0]['DATA'][names[i]].length;j++) {
allNames.push(json[0]['DATA'][names[i]][j]['NAME']);
}
}
return allNames.sort();
}
called using:
allNames(['array_1','array_2']);
Seems to work.