Updating the value of an object inside a loop using javascript - javascript

I'm currently facing a difficulty in my codes.
First i have an array of objects like this [{Id:1, Name:"AML", allowedToView:"1,2"}, {Id:2, Name:"Res", allowedToView:"1"}...] which came from my service
I assign it in variable $scope.listofResource
Then inside of one of my objects I have that allowedToView key which is a collection of Id's of users that I separate by comma.
Then I have this code...
Javascript
$scope.listofResource = msg.data
for (var i = 0; i < msg.data.length; i++) {
First I run a for loop so I can separate the Id's of every user in allowedToView key
var allowed = msg.data[i].allowedToView.split(",");
var x = [];
Then I create a variable x so I can push a new object to it with a keys of allowedId that basically the Id of the users and resId which is the Id of the resource
for (var a = 0; a < allowed.length; a++) {
x.push({ allowedId: allowed[a], resId: msg.data[i].Id });
}
Then I put it in Promise.all because I have to get the Name of that "allowed users" base on their Id's using a service
Promise.all(x.map(function (prop) {
var d = {
allowedId: parseInt(prop.allowedId)
}
return ResourceService.getAllowedUsers(d).then(function (msg1) {
msg1.data[0].resId = prop.resId;
Here it returns the Id and Name of the allowed user. I have to insert the resId so it can pass to the return object and it will be displayed in .then() below
return msg1.data[0]
});
})).then(function (result) {
I got the result that I want but here is now my problem
angular.forEach(result, function (val) {
angular.forEach($scope.listofResource, function (vv) {
vv.allowedToView1 = [];
if (val.resId === vv.Id) {
vv.allowedToView1.push(val);
I want to update $scope.listofResource.allowedToView1 which should hold an array of objects and it is basically the info of the allowed users. But whenever I push a value here vv.allowedToView1.push(val); It always updates the last object of the array.
}
})
})
});
}
So the result of my code is always like this
[{Id:1, Name:"AML", allowedToView:"1,2", allowedToView:[]}, {Id:2, Name:"Res", allowedToView:"1", allowedToView:[{Id:1, Name:" John Doe"}]}...]
The first result is always blank. Can anyone help me?
Here is the plunker of it... Plunkr

Link to the solution - Plunkr
for (var i = 0; i < msg.length; i++) {
var allowed = msg[i].allowedToView.split(",");
msg[i].allowedToView1 = [];
var x = [];
Like Aleksey Solovey correctly pointed out, the initialization of the allowedToView1 array is happening at the wrong place. It should be shifted to a place where it is called once for the msg. I've shifted it to after allowedToView.split in the first loop as that seemed a appropriate location to initialize it.

Related

Why can't I push this additional data into my array?

I'm making an API call and here is the response
As you can see, key 0 & 1 have NULL for their 'outcome_status' whereas key 2 is populated. The number of returned results is dynamic
I wish to loop the results and push the 'category' & 'location' details into the array and if 'outcome_status' isn't NULL then I wish to add that data into the same array.
The problem is, within the IF statement that checks if outcome_status is null, I can't assign the forloop var i; variable as the key for
mapData where I use.push() the second time.
line:68 Uncaught TypeError: Cannot read property 'push' of undefined
var mapData = [];
function getPolApi(year,month,lat,lng,mapData) {
$.ajax({
url : "https://data.police.uk/api/crimes-at-location?date="+year+"-"+month+"&lat="+lat+"&lng="+lng,
type : "get",
async: false,
success : function(data) {
console.log(data);
mapData = [];// Empty the array of old results
for(var i = 1; i < data.length; i++) {
EDIT: I want to do this.
mapData.push([
data[i]['category'],
data[i]['location']['street']['name'],
data[i]['outcome_status']['category'],
data[i]['outcome_status']['date']
]);
But if there is no outcome_status then it will fail... So I added the second part into a conditional instead
if(data[i].outcome_status != null) {
//In order to access the original array by key,
// I wish to the use the forloop iteration otherwise
//mapData.push() will add the data as NEW arrays instead of adding on to the end of the existing arrays.
//Why can't I use the current index for the key here?
mapData[i].push([ //line 68
data[i]['outcome_status']['category'],
data[i]['outcome_status']['date'],
]);
}
heatmapData.push(new google.maps.LatLng(data[i].location.latitude,data[i].location.longitude));
}
console.log(mapData);
//Add results into view
for(var i = 0; i < mapData.length; i++) {
var fill = '<div class="row resu"><div class="col-xs-2 number"><h5>'+[i+1]+'</h5></div><div class="col-xs-10"><p class="text-primary">Type of crime: <span class="text-strong">'+mapData[i][0]+'</span></p><p class="text-primary">Location specifics: <span class="text-strong">'+mapData[i][1]+'</span></p></div></div>';
$('.output').append(fill);
}//endforloop
//Move the map into view of the heatmaps
moveMap(lat,lng);
//Add the heatmaps
addHeatMap();
// console.log(mapData);
},
error: function(dat) {
console.log('error');
}
});
Some issues:
Your for loop starts with i equal to one, so even after the first push, mapData[i] does not yet exist, so applying push to that makes no sense.
If you want to push additional elements to an existing array, you should not add those additional elements as part of an array, but provide them as separate arguments to push.
Furthermore, the code becomes a bit more functional when use array methods like map.
Here is how the part to fill mapData and heatmapData could look like:
// Create a new array, with nested arrays: one per data item
mapData = data.map(function (item) {
// Use a local variable to build the sub-array:
var arr = [
item.category,
item.location.street.name,
];
if (item.outcome_status) { // add 2 more elements if they exist
arr.push( // note: no square brackets here
item.outcome_status.category,
item.outcome_status.date,
);
}
// Add it to `dataMap` by returning it to the `map` callback:
return arr;
});
// Extend the heatmap with additional locations
heatmapData = heatmapData.concat(data.map(function (item) {
return new google.maps.LatLng(item.location.latitude,item.location.longitude);
}));
The Issue:
Here, you initialize i as 1:
for(var i = 1; i < data.length; i++) {
You then push one item to mapData[]:
mapData.push([
data[i]['category'],
data[i]['location']['street']['name'],
]);
A couple lines later, you try to access mapData[i]...
mapData[i].push([
data[i]['outcome_status']['category'],
data[i]['outcome_status']['date'],
]);
This is trying to access mapData[1], but mapData[] only has one item at this point. You need mapData[0].
The Solution:
Try simply changing your i to initialize as 0 instead of 1:
for(var i = 0; i < data.length; i++) {
If this is not sufficient and data[] needs to be a 1-index, then perhaps mapData[i-1] instead of mapData[i] would suit your needs.

How can I dynamically index through datalayer tags in GTM?

I'm using the DuracellTomi datalayer plugin to push cart data from woocommerce to a GTM model to handle some tracking.
The DuracellTomi plugin pushes content to the transactionProducts[] array in the following format:
transactionProducts: Array[1]
0 : Object
category:""
currency:"USD"
id:8
name:"Test"
price:100
quantity:"1"
sku:8
I'd like to loop through this array and unstack it into three separate arrays, pricelist, skulist, and quantitylist. Currently I anticipate doing so as some variation on
//Get Product Information
if(stack = {{transactionProducts}}){
for(i = 0; i < stack.length; i++) {
if(stack.i.sku){
skulisttemp.i = stack.i.sku;
}
if(stack.i.price){
pricelisttemp.i = stack.i.price;
}
if(stack.i.sku){
quantitylisttemp.i = stack.i.quantity;
}
}
{{skulist}} = skulisttemp;
{{pricelist}} = pricelisttemp;
{{quantitylist}} = quantitylisttemp;
}
Obviously this is not going to work because of how the tag referencing is set up, but I'm wondering if anyone has dealt with this and knows what the best way to index through these arrays might be. (For those who don't know, the square bracket array call doesn't work with GTM variables and instead the . format is used instead.)
You would need to create 3 variable type custom javascript function that picks your required value from dataLayer and returns it in an array.
Something like
function(){
var products = {{transactionProducts}};
var skuArray = [];
for(i = 0; i < products.length; i++) {
if(products[i].sku){
skuArray.push(products[i].sku)
}
}
return skuArray
}
hope this helped you :)

How to store a Facebook Graph API response as a Javascript Array?

I'm wondering how to store the response from a Facebook API call into a Javascript array.
This is the call I'm making:
FB.api('/MYAPPID/scores/?fields=user', function(response) {
for (var i = 0; i < response.data.length; i++){
var grabbedarray = response.data[i].user.id;
console.log(grabbedarray);
}
})
The call FB.api('/MYAPPID/scores/?fields=user' returns a data set that has "name" and "id" properties for each element in the array, but I'm only interested in storing the "id" parts of the array.
The above code iterates through the response from the call, it checks user.id in each row of the array, and then the console.log shows the id for that row. This means that var grabbedarray is appearing several times in the console, showing a different id each time. I understand why this is happening, but I'm trying to get all the ids stored into one array, and then I'd like to console.log that.
So the final result in the console should be something like:
[456345624, 256456345, 253456435727, 376573835, 2652453245]
I've tried changing the call to FB.api('/MYAPPID/scores/?fields=user.id' in the hope that the response will show only a list of ids, but it's not working.
Does anyone have any idea how to solve this problem?
Thank you in advance!
To keep the approach you were using, you can push each new id you find into an array you define outside of the for loop.
var idArray = [];
FB.api('/MYAPPID/scores/?fields=user', function(response) {
for (var i = 0; i < response.data.length; i++){
idArray.push(response.data[i].user.id);
}
console.log(idArray);
})
You could also use map to transform the response array into what you want.
var idArray = [];
FB.api('/MYAPPID/scores/?fields=user', function(response) {
idArray = response.data.map(function(x){ return x.user.id });
console.log(idArray);
})

My update tag function here isn't working

Hi all I am new to angular and would like to know what I am doing wrong in this function.
I am trying to retrieve a firebase child array of tags and compare it with users tags and get an union and post that union back to the firebase array .
Here is my function:
//this retrieved the tag arrays from firebase
$scope.utags = Tag.gettag();
This function converts a firebase array to a JS array .. I initialize it with {{universaltags(utags)}} from the view. Any attempt to initiate the function in the controller using $scope.unversaltags($scope.utags); gives me a blank array
but it works with the views initiation.
$scope.universaltags = function(utag){
var arr1 = [];
for (var i = 0 ; i < utag.length; i++) {
arr1.push(utag[i].$value);
}
return arr1;
};
Also this is the function which I use to find the union and post it back to firebase.
$scope.universaltagupdate = function union_arrays (x,y,Tag) {
var obj = {};
for (var i = x.length-1; i >= 0; -- i) {
obj[x[i]] = x[i];
}
for (var i = y.length-1; i >= 0; -- i) {
obj[y[i]] = y[i];
}
var res = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) { // <-- optional
res.push(obj[k]);
}
}
//this uses a service to set firebase value
return Tag.updatetag(res);
}
I am not able to initialize both the functions within the controller.
Can you please tell me what is wrong with this approach and what can be the best way to achieve the result? Right now using the functions in curly braces show the results, but how do I accomplish this in the controller?

JavaScript stop referencing object after pass it to a function

I know JavaScript passes Objects by reference and thus I'm having a lot of trouble with the following code:
function doGradeAssignmentContent(dtos) {
var x = 5;
var allPages = [];
var stage = new App.UI.PopUpDisplay.PopUpStageAssignmentGrader(null, that);// pass launch element
for(var i = 0; i < dtos[0].result.students.length; ++i) {
var pagesSet = [];
for(var j = 0; j < dtos[0].result.questions.length; ++j) {
var questionObject = jQuery.extend(true, {}, new Object());
questionObject = dtos[0].result.questions[j];
if(dtos[0].result.students[i].answers[j].assignmentQuestionId === questionObject.questionId) {// expected, if not here something is wrong
questionObject.answer = dtos[0].result.students[i].answers[j].studentAnswer;
questionObject.pointsReceived = dtos[0].result.students[i].answers[j].pointsReceived;
} else {
var theAnswer = findAssociatedStudentAnswer(questionObject.questionId, dtos[0].result.students[i].answers[j]);
if(theAnswer !== null) {
questionObject.answer = theAnswer.studentAnswer;
questionObject.pointsReceived = theAnswer.pointsReceived;
} else {
alert("Unexpected error. Please refresh and try again.");
}
}
pagesSet[pagesSet.length] = new App.UI.PopUpDisplay.StageAssignmentGradingPages[dtos[0].result.questions[j].questionType.charAt(0).toUpperCase() + dtos[0].result.questions[j].questionType.slice(1) + "QuestionAssignmentGradingPage"](j + 1, questionObject);
}
var studentInfo = {};
studentInfo.avatar = dtos[0].result.students[i].avatar;
studentInfo.displayName = dtos[0].result.students[i].displayName;
stage.addPageSet(pagesSet, studentInfo);
}
stage.launch();
}
First let me show you what the result (dtos) looks like so you can better understand how this function is parsing it:
The result (dtos) is an Object and looks something like:
dtos Array
dtos[0], static always here
dtos[0].result, static always here
dtos[0].questions Array
dtos[0].questions.index0 - indexN. This describes our Questions, each one is an Object
dtos[0].students Array
dtos[0].students[0]-[n].answers Array. Each student array/Object has an Answers array. Each student will have as many elements in this answers Array that there were questions in dtos[0].questions. Each element is an Object
Now what we do in this here is create this Object stage. Important things here are it has an array called "this.studentsPages". This array will ultimately have as many entries as there were students in dtos[0].students.
So we loop through this for loop disecting the dtos array and creating a pagesSet array. Here comes my problem. On the first iteration through the for loop I create this questionObject element. I also have tried just doing var questionObject = {}, but what you see now was just an attempt to fix the problem I was seeing, but it didn't work either.
So at the end of the first iteration of the outer for loop I call stage.addPageSet, this is what happens here:
var pageObject = [];
pageObject["questions"] = pageSet;
pageObject["displayName"] = studentInfo.displayName;
this.studentsPages[this.studentsPages.length] = pageObject;
if(this.studentsPages.length === 1) {// first time only
for(var i = 0; i < pageSet.length; ++i) {
this.addPage(pageSet[i]);
}
}
The important thing to take notice of here is where I add pageObject on to this.studentsPages which was an empty array before the first call. pageObject now has pageSet plus a little bit more information. Remember, pageSet was an Object and thus passed by reference.
On the next iteration of the for loop, when I hit this line:
questionObject.answer = dtos[0].result.students[i].answers[j].studentAnswer;
It goes wrong. This changes the local copy of questionObject, BUT it also changes the copy of questionObjec that was passed to addPageSet and added to the studentsPages array in the first iteration. So, if I only had 2 students coming in, then when all is said and done, studentsPages hold 2 identical Objects. This should not be true.
The problem is questionObject in the doGradeAssignmentContent function is keeping a reference to the Object created on the previous iteration and then overrides it on all subsequent iterations.
What can I do to fix this?
Thanks for the help!
With out having looked at it too closely I believe you need to change the following:
// Before:
var questionObject = jQuery.extend(true, {}, new Object());
questionObject = dtos[0].result.questions[j];
// After:
var questionObject = jQuery.extend(true, {}, dtos[0].result.questions[j]);
I didn't look too closely if there are other instances in the code where this needs to be applied, but the core concept is to utilize jQuery's deep copy to generate a duplicate of the object you do not wish to retain a reference to.

Categories

Resources