For..In Loop Overwriting ALL Array Values - javascript

I'm trying to use a for..in loop to iterate through a list of names, add them to a template object ('group'), then add each complete object to an array ('queryList'). This isn't working because each iteration is overwriting ALL values in the array. Any suggestions why this is happening?
// BATTERY OBJECT
var groupList = [ "LOGIN", "BROWSE", "SEARCH"];
// GROUP OBJECT
var group = {dbName: 'CARS', name: '', collectionName: 'group'};
// INIT VARS
var groupName = '',
queryList = [];
// COMPILATION FUNCTION
var buildGroupQueries = function(group){
// BUILD BATCH OF QUERIES
for (var i in groupList){
groupName = groupList[i];
group.name = groupName;
queryList[i] = group;
}
console.log(queryList);
}
buildGroupQueries(group);
It should look like:
[
{"dbName":"CARS","name":"LOGIN","collectionName":"group"},
{"dbName":"CARS","name":"BROWSE","collectionName":"group"},
{"dbName":"CARS","name":"SEARCH","collectionName":"group"}
]
Instead I'm getting:
[
{"dbName":"CARS","name":"SEARCH","collectionName":"group"},
{"dbName":"CARS","name":"SEARCH","collectionName":"group"},
{"dbName":"CARS","name":"SEARCH","collectionName":"group"}
]

You are creating an array of elements referring to the same object, so they all show the same name coinciding with the last time you changed it, which is "SEARCH" in your example.
You have to refer each element to a new object created from the one you want to use as a template.
To do so you can either loop over its properties or clone it as shown below:
// BATTERY OBJECT
var groupList = [ "LOGIN", "BROWSE", "SEARCH"];
// GROUP OBJECT
var group = {dbName: 'CARS', name: '', collectionName: 'group'};
// INIT VARS
var groupName = '',
queryList = [];
// COMPILATION FUNCTION
var buildGroupQueries = function(group){
var i, _group;
// BUILD BATCH OF QUERIES
for (i in groupList){
_group = JSON.parse(JSON.stringify(group));
groupName = groupList[i];
_group.name = groupName;
queryList[i] = _group;
}
console.log(queryList);
}
buildGroupQueries(group);

You modify the group object each time, but you need to modify its copy.
Add this code just after your line for (var i in groupList){
var _group = {};
for (var j in group){ _group[j] = group[j]; }
On each iteration you create a new object and copy to it all properties from the master object.

Related

How to push additional fields to a javascript array from an oData result

I have a ramdom array in javascript
var dataModel = [];
I've queried an oData url and I want to fill the result in my dataModel [] array. And, for each item I want to add additional fields
odataMod.read(
"/",
null, [],
true,
function (oData, oResponse) {
var data = oData.results;
data.forEach(function (item) {
//Add the object
dataModel.push(item);
//I want to add additional fields to every object in data
dataModel.push(item.ObjectType = "Chevron");
dataModel.push(item.HierarchyNodeLevel = 0);
dataModel.push(item.IsCriticalPath = false);
dataModel.push(item.IsProjectMilestone = false);
dataModel.push(item.DrillDownState = "expanded");
dataModel.push(item.Magnitude = 5);
...
Note : the ObjectType , DrillDownState , Magnitude (etc...) are the fields that I want to add with their values Chevron, 0, false (etc...)
Below is a screenshot of the current result :
But I want to add the additional properties inside each item and not outside , what I am doing wrong? In other word, I want the additional fields to be inside the metadata
Below is a sc of where I would like to add the items :
Maybe I'm misunderstanding, but I think you want only one push per item in the response. The other pushes ought to be replaced with setting properties on a copy of the item...
data.forEach(function (item) {
item.ObjectType = "Chevron";
item.HierarchyNodeLevel = 0;
item.IsCriticalPath = false;
item.IsProjectMilestone = false;
item.DrillDownState = "expanded";
item.Magnitude = 5;
dataModel.push(item); // note: just one push
// alternatively, so as to not mutate item...
// const dataModelItem = Object.assign({
// ObjectType: "Chevron",
// HierarchyNodeLevel: 0,
// etc.
// }, item);
// dataModel.push(dataModelItem);
}

javascript array as values in associated array

I am trying to build an associated array dynamically like this.
How do I build it? With the following expected output?
"happy": [1,2,3,4,5],
"angry": [6,7,8,9,10]
$(document).ready(function() {
var videos = [];
$('.header-video__media').each(function(i, elem) {
var mediaElement = $(elem);
var mood = mediaElement.attr('data-mood');
headerVideo = new HeaderVideo({
index:i,
element: '.header-video',
media: '.header-video__media',
playTrigger: '.header-video__play-trigger',
closeTrigger: '.header-video__close-trigger',
nextTrigger: '.header-video__next-trigger'
});
videos.mood = mood;
videos.push (headerVideo);
});
In the JavaScript world associative array are represented by literal objects:
// declaration of a new literal object
var videos = {};
// test if the key is already setted or not
if(!videos.hasOwnProperty(mood)){
// if not, initiate a new array
videos[mood] = [headerVideo];
}else{
// if yes, add add the value to the existing array
videos[mood].push(headerVideo);
}

Filter properties from an array based on another array

I have an array of objects like this:
var bridges = {"countyCd:15
createdDate:"0001-01-01T00:00:00"
createdUserId:0
createdUserIdZ:null
createdUserName:null
description:"SR 1#.-CENTRAL RR COMP OF IND"
districtId:null
encryptedId1:null
encryptedId2:null
isDirty:false
modelState:null
nbiNumber:10
routeNbr:"1"
routeTypeCd:"SR"
transactionType:null
updatedDate:"0001-01-01T00:00:00"
updatedUserId:0
updatedUserIdZ:null
updatedUserName:null", [...]....}
I have another array like this
[countyCd, nbiNumber]
How can create another array keeping just two properties so it becomes like
bridges = {"countyCd:15
nbiNumber:10"
, [...]....}
Basically, I am looking for a way to create a function that takes a data array and a filter array as parameters and filters the data array based on the filter array.
Any pointers to this will be much appreciated.
One solution would be to map over each record and reduce your filter array into an object containing the target proprties:
var bridges = [{
countyCd:15,
createdDate:"0001-01-01T00:00:00",
createdUserId:0,
createdUserIdZ:null,
createdUserName:null,
description:"SR 1#.-CENTRAL RR COMP OF IND",
districtId:null,
encryptedId1:null,
encryptedId2:null,
isDirty:false,
modelState:null,
nbiNumber:10,
routeNbr:"1",
routeTypeCd:"SR",
transactionType:null,
updatedDate:"0001-01-01T00:00:00",
updatedUserId:0,
updatedUserIdZ:null,
updatedUserName:null
}, {
countyCd:23,
createdDate:"0001-01-01T00:00:00",
createdUserId:0,
createdUserIdZ:null,
createdUserName:null,
description:"SR 1#.-CENTRAL RR COMP OF IND",
districtId:null,
encryptedId1:null,
encryptedId2:null,
isDirty:false,
modelState:null,
nbiNumber:10,
routeNbr:"1",
routeTypeCd:"SR",
transactionType:null,
updatedDate:"0001-01-01T00:00:00",
updatedUserId:0,
updatedUserIdZ:null,
updatedUserName:null
}];
var filters = ['countyCd', 'nbiNumber'];
var transformedRecords = bridges.map(bridge => filters.reduce((p, c) => {
p[c] = bridge[c];
return p;
}, {}));
console.log(transformedRecords);
Say you have an array of bridges, call it bA:
var bA = []; //bridges array
var nbiA = []; // nbia array with countyCd
var newA = []; // new array
bA.forEach(function(element, index, array){
var newEntry = {
'countyCd':element.countyCd,
'nbiNumber':nbiA.find(function(nbi){
return nbi[countyCd] == element.countyCd;
}).nbiNumber
};
newA.push(newEntry);
});
//do whatever you want with the newA array

Best way to store this data (array, object, etc)

I need to store (many) objects or arrays of data, which need to have the following criteria:
I need to be able to add a new set of data into the existing data easily
I need to be able to sort the data by date/ time added easily (array in order of when entries were pushed to it)
I need to be able to grab an entry easily using a reference, either integer or string. This is important, at the moment I have to do an $.each() to loop through my data until I find the entry I want.
I have tried using a structure like:
saved_info = {
1001: {//all my data for ref 1001},
1002: {//all my data for ref 1002}
}
which gave me what wanted of being able to grab the info easily given a reference:
info = saved_info[1001];
however, the reference numbers I use aren't in order - I use a reference given to me (its a unique identifier), therefore the object isn't in order of when items were added/saved/pushed.
You can use two objects:
One that stores the data by key
Another that stores the sort order
This way you can (i) lookup an element by key (ii) loop over elements in the order they were inserted. Rough outline of the structure:
var DataObject = {
data: {},
sort: []
};
Here is how you add data to this structure:
DataObject.data[1004] = {name: "Test 4"};
DataObject.sort.push(1004);
DataObject.data[1001] = {name: "Test 1"};
DataObject.sort.push(1001);
DataObject.data[1003] = {name: "Test 3"};
DataObject.sort.push(1003);
DataObject.data[1002] = {name: "Test 2"};
DataObject.sort.push(1002);
Here is how you perform a random access:
console.log(DataObject.data[1001].name);
console.log(DataObject.data[1003].name);
And here is how you iterate over all elements in the order they were added:
var i;
for (i = 0; i < DataObject.sort.length; i++) {
console.log(DataObject.data[DataObject.sort[i]].name);
}
It is possible to wrap the entire logic inside a class:
function DataObject() {
this.data = {};
this.sort = [];
this.setItem = function (k, v) {
this.data[k] = v;
this.sort.push(k);
};
this.getItemByKey = function (k) {
return this.data[k];
};
this.getItemByPos = function (i) {
return this.data[this.sort[i]];
};
this.getAllItems = function () {
var i, r = [];
for (i = 0; i < this.sort.length; i++) {
r.push(this.data[this.sort[i]]);
}
return r;
};
}
var t = new DataObject();
t.setItem(1001, {name: "Test 1"});
t.setItem(1002, {name: "Test 2"});
t.setItem(1003, {name: "Test 3"});
t.setItem(1004, {name: "Test 4"});
console.log(t.getItemByKey(1001));
console.log(t.getItemByPos(0));
console.log(t.getAllItems());
Try to build a Json like this,
var xJson = {
"1001":{//all my data for ref 1001},
"1002":{//all my data for ref 1002}
};
and you can fetch the records as per your wish using the bracket notation, since we are using a numeric value as a key.
var xData = xJson["1001"];

Populating Javascript Array of Objects with an embedded Array of Objects

I am new to Javascript (familiar with C/C++) and I am trying to parse out an XML file and store it in an Array of Objects. The structure is similar to a bullet list where there is one main List item and possibly multiple List subitems:
var MenuLine =
[{
label : "null",
icon : "null",
Subitem:
[{
label : "null",
icon : "null"
}]
}];
Which allows me to use the following syntax:
var someRandomSubitemText = MenuLine[2].Subitem[4].label;
I tried populating this array using the .push method:
var tempMenuLine = [];
var tempSubitem = [];
$(xml).find("item").each(function()
{
tempMenuLine.label = $(xml).children("label").text();
tempMenuLine.icon = $(xml).children("icon").text();
$(this).children("subitem").each(function()
{
tempSubitem.label = $(this).children("label").text();
tempSubitem.icon = $(this).children("icon").text();
tempMenuLine.Subitem.push(tempSubitem);
});
MenuLine.push(tempMenuLine);
});
However this does not work since the .push method passes a reference to tempMenuLine and I am overwriting tempMenuLine with each iteration. Is there a way that I could write directly to the MenuLine array using something similar to the following syntax?
$(xml).find("item").each(function(index1)
{
MenuLine[index1].label = $(xml).children("label").text();
MenuLine[index1].icon = $(xml).children("icon").text();
$(this).children("subitem").each(function(index2)
{
MenuLine[index1].Subitem[index2].label = $(this).children("label").text();
MenuLine[index1].Subitem[index2].icon = $(this).children("icon").text();
});
});
Move your temp var declarations inside of your loops:
$(xml).find("item").each(function() {
var tempMenuLine = [];
tempMenuLine[0].label = $(xml).children("label").text();
tempMenuLine[0].icon = $(xml).children("icon").text();
tempMenuLine[0].Subitem = []
$(this).children("subitem").each(function(){
var tempSubitem = [];
tempSubitem[0].label = $(this).children("label").text();
tempSubitem[0].icon = $(this).children("icon").text();
tempMenuLine[0].Subitem.push(tempSubitem);
});
MenuLine.push(tempMenuLine);
});
This way, you're initializing a new item for each iteration of the loops, removing the "link" it had to the previous item.
A recursive solution just for fun.
var MenuLine = Xml2Array(xmlText, 'item');
function Xml2Array(xmlDocument, itemName) {
if (!$(itemName, xmlDocument).length) {
return;
}
var tmpArray = [];
$(itemName, xmlDocument).each(function() {
tmpArray.push({
label: $('label', this).first().text(),
icon: $('icon', this).first().text(),
Subitem: Xml2Array(this, 'subitem')
});
});
return tmpArray;
}

Categories