array.forEach works, but not when I nest another inside - javascript

I've got two pages I'm working on, and both return an array of objects. When I use the following code, the new results work:
this.adminService.waiversGetAll()
.subscribe((data: Waiver[]) => {
this.waivers = data;
this.waivers.forEach((e) => {
if(e.has_signed === true) {
e.url = `View`
} else {
e.url = `${e.message}`;
}
return e;
});
console.log(this.waivers);
})
}
But when I try to do the same thing with a different array (where I need to update the values of an array nested inside) I don't get updated values:
this.adminService.GetUnsignedWaivers()
.subscribe((data: Player[]) => {
console.log("data",data);
data.forEach(e => {
let record: Object = {};
for(let i = 0; i < e.waivers.length; i++) {
console.log(e.waivers[i].has_signed);
if (e.waivers[i].has_signed === true) {
e.waivers[i].url = e.waivers[i].signatureUrl;
console.log(e.waivers[i].url);
e.waivers[i].message = "View Waiver";
} else {
e.waivers[i].url = e.waivers[i].url;
e.waivers[i].message = e.waivers[i].message;
}
console.log(e.waivers[i].message);
return;
};
return e;
});
this.size = this.players.length;
console.log(this.players);
})
}
When I look at the console.log of e.waivers[i].has_signed, the data is correct, but after that it's not right.
What do I have to do to make this work? I've tried using a for loop inside the foreach, and a bunch of other stuff.
The data supplied to the loop provides info like:
{
buyer: "email#someaddress.edu"
event: "COED A"
field: "Main"
net: null
player: {shirtSize: null, avp_id: 12345678, adult: true, …}
team: null
waivers: [{
email: "someemail#gmail.com",
has_signed: true,
message: "Liability Waiver",
signatureUrl: "https://somelink.pdf",
url: "https://somelink.com/somekeyidentifier"
}
IF the player has signed the waiver, there will be a signatureUrl field and the message should say "View Waiver" instead of the message telling me what type of waiver they will sign. I want the url to be set to signatureUrl if they signed, so I can use it in a table that doesn't like manipulation of data.
A visual of what is returned in my table:
All I get is 1600 records showing the url as though everyone hasn't signed, but when I console.log has_signed in the inner loop, it's showing TRUE for the ones that should show a signatureUrl instead.

Quickly looking at it, you have a return statement within your for loop, which would stop it from running after the first iteration.

First of all drop all the return statements in your code. Next, use map instead of forEach as the former returns you the new manipulated array and the latter is used just for iteration purpose.
Your code within subscribe then becomes:
data.waivers = data.waivers.map((waiver) => {
if (waiver.has_signed) {
// your logic goes here...
waiver.url = waiver.signatureUrl;
waivers.message = "View Waiver";
}
// No else is required as you are just reassigning with same values
});
this.playerDetails = data;
At last bind this modified data in your template.

Related

Why does my forEach() loop only execute once?

I seem to have encountered a problem while looping through an array. The loop seems to only execute once, no matter the size of the array. I tried using different methods of looping and the error still persists.
As background information, I'm trying to make a bot with which users can award each other points. Everything else seemed alright. The only issue is that I wish to set up a maximum amount of points one user can give to another in a day, and I'm having problems looping through the array which stores this information.
These are the relevant parts of my code:
var timer = []; //Timer stores the values.
const getTimerSenderIdTable = (id) => {
let found = false;
timer.forEach(function(dat) { // This is the problematic loop.
if (dat.id === id) {
found = dat;
}
})
console.log("loop end, results: " + found);
return found;
};
const timerManager = (senderId, targetId, pointSurp) => { //All arguments are integers.
let d = new Date()
if (getTimerSenderIdTable("date") !== d.getDate()) {
timer = [];
timer.push({"id":"date", "time":d.getDate()});
if (getTimerSenderIdTable("date")) {
if (getTimerSenderIdTable(senderId)) {
console.log("path 1");
} else {
console.log("path 2");
timer.push({"id":senderId, [targetId]:pointSurp});
}
}
} else {
if (getTimerSenderIdTable("date")) {
if (getTimerSenderIdTable(senderId)) {
console.log("path 3");
} else {
console.log("path 4");
timer.push({"id":senderId, [targetId]:pointSurp});
}
}
}
console.log(timer)
};
*Edit:
Thank you for your comments. Here is an example:
Calling timerManager(123456, 654321, 3) will produce the following output:
loop end, results: false
loop end, results: [object Object]
loop end, results: false
path 2
[ { id: 'date', time: 28 }, { '654321': 3, id: 123456 } ]
(This is a repost from comments. My appologies.)
It seems because of this line
if (getTimerSenderIdTable("date") !== d.getDate()) {
timer = [];
This will empty the array and next lines of code will only push single element
as #mbojko has pointed out, you'll want to use the find method for returning the found obj inside getTimerSenderIdTable function, like this
const getTimerSenderIdTable = (id) => {
return timer.find(item => item.id === id});
};

how to compare objects values in 2 identical lists in javascript

i have two collections in mongo db that hold reports, in report there is list matches, so what i want is to run on production reports and for ech one check in staging reports and check that if the matches are the same length if the personId and addressId are also the same...
is there a a good way to do this?
i came up with something like this:
db.production_reports.find({}).forEach((prodRep)=> {
db.reports.find({_id: prodRep._id}).forEach((stagingRep)=> {
if (prodRep.matches.length == stagingRep.matches.length) {
prodRep.matches.forEach((match)=> {
var res = stagingRep.matches.filter(element => element.personId == match.personId && element.addressId == match.addressId);
if (res) {
print("yay")
} else {
print("nay")
}
});
}
});
});
i want for each report the script to tell me "yes, all matches equal", or print the reportId that have non equal matches
thanks
I would draft something like this :
return new Promise((resolve) => {
const data = {
// contains an array of _id of missing production_reports
missing: [],
different: [],
};
// Look at each entry in production_reports
db.production_reports.find({})
.cursor()
.eachAsync(async (x) => {
// get the similar data on reports
const copy = await db.reports.find({
_id: x._id,
});
// If the data doesn't exists into reports
if (!copy || !copy.length) {
data.missing.push(x._id);
return;
}
// If it exists, compare the inner values
// if the size isn't the same, it's obviously different
if (x.matches.length !== copy.length) {
data.different.push(x._id);
return;
}
// Check every element of match one by one
if (x.matches.some(y => !copy.matches.some(z => z.personId === y.personId))) {
data.different.push(x._id);
}
}, {
// How many items do we look at same time
parallel: 250,
}, () => {
// When we are done processing all items
resolve(data);
});
});
NOTE : It won't give you missing documents that exists in reports but not in production_reports

How to make the if conditions look cleaner?

Is there a way to make this if conditions look cleaner and easily to add more Query search in the future as in Open–closed principle?
For example:
if (event.queryParameters["name"]) {
result = await getResultByName(event.queryParameters["name"]);
} else if (event.queryParameters["emailAddress"]) {
result = await getResultByEmail(event.queryParameters["emailAddress"]);
} else if (event.queryParameters["param1"]) {
result = await getResultByParam1(event.queryParameters["param1"]);
} else if (event.queryParameters["something1"] && event.queryParameters["something2"]) {
result = await getResultBySomething(event.queryParameters["something1"], event.queryParameters["something2"]);
}
As you can see it look really messy.
Make a table of entries and use Array.prototype.find():
const lut = [
{ keys: ['name'], getResultBy: getResultByName },
{ keys: ['emailAddress'], getResultBy: getResultByEmail },
{ keys: ['param1'], getResultBy: getResultByParam1 },
{ keys: ['something1', 'something2'], getResultBy: getResultBySomething }
]
const params = event.queryParameters
const entry = lut.find(
({ keys }) => keys.every(key => key in params)
)
if (entry) {
const { keys, getResultBy } = entry
const result = await getResultBy(...keys.map(key => params[key]))
...
}
The problem with the original code is that it isn't DRY, and so any incremental modification will inevitably repeat what was already written.
Compare the following two incremental changes:
...
{ keys: ['fizz', 'buzz', 'fizzbuzz'], getResultBy: getResultByFizzBuzz }
...
else if (params.fizz && params.buzz && params.fizzbuzz) {
result = await getResultByFizzBuzz(params.fizz, params.buzz, params.fizzbuzz);
}
And tell me which one you'd rather be typing every time you go back and add a new function.
Since values are different and functions are different, there's not much place for improvement.
There's no necessity for bracket notation and there's no reason to reference event object every time.
It could be written as:
const { queryParameters } = event;
if (queryParameters.name) {
result = await getResultByName(queryParameters.name);
} else if ...
No other improvements can be made, unless the same case occurs in several places and could be DRYed up:
const paramHandlers = [
{ handler: getResultByName, paramNames: ['name'] },
...
];
Then paramHandlers can be iterated to check if paramNames match event.queryParameters properties.
So what you have looks perfectly readable, simple, and clean. You could create an event handler list if you need more flexibility:
eventHandlers = [nameHandler, emailHandler, ...];
var result;
for (var handler of eventHandlers) {
if (result = handler(event)) break;
}
In this example, the event handlers are functions that return a result if the event was consumed and processing should end. In your case your result can be a Promise or any arbitrary value.

how to get distinct value from angularjs loop

I made a loop in angularjs and i want to get a distinct values from this loop then push it to an array.
What I got instead, are repetitive values.
The $scope.Empassignedvacations returns multiple data from datatable from db. one column from it is vac which displays multiple vacations keys in the db.
What i want to do is to take these keys and distinct them and push them to another $scope array. its name is $scope.checkedvacs. but i got 2,2,2,2,20,20,20,20
Assignments.getvacations().then(function (response) {
$scope.vacations = (response.data);
Assignments.GetEmpassignedvacations($scope.SelectedEmp1.staffkey)
.then(function (response) {
$scope.Empassignedvacations = (response.data)
$scope.checkedvacs.push( $scope.Empassignedvacations.vac );
angular.forEach($scope.Empassignedvacations, function (e) {
angular.forEach($scope.AlternateDirector, function (a) {
if (e.Staff_Key == a.Staff_Key) {
$scope.AlternateD = e.AlternateD;
}
})
angular.forEach($scope.status, function (s) {
if (e.status == s.stsid) {
$scope.sts = s.stsid;
}
})
})
Thanks in advance
It happens because you play with the same value $scope.Empassignedvacations.
You push it to the array and after - change it. This is a reason why you get 2,2,2,2,20,20,20,20
So you can fix it by pushing the copy of the value, like:
$scope.checkedvacs.push( angular.copy($scope.Empassignedvacations.vac));
First declare $scope.checkedvacs=[] & $scope.keys=[] in globally for standard code practice then try bellow code
angular.forEach($scope.Empassignedvacations.vac, function(item) {
// we check to see whether our object exists
$scope.keys = item[keyname];
// if it's not already part of our keys array
if ($scope.keys.indexOf(key) === -1) {
// push this item to our final output array
$scope.checkedvacs.push(item);
}
});
remove bellow code and replace your code with first code sample..
$scope.checkedvacs.push( $scope.Empassignedvacations.vac );
angular.forEach($scope.Empassignedvacations, function (e) {
angular.forEach($scope.AlternateDirector, function (a) {
if (e.Staff_Key == a.Staff_Key) {
$scope.AlternateD = e.AlternateD;
}
})
angular.forEach($scope.status, function (s) {
if (e.status == s.stsid) {
$scope.sts = s.stsid;
}
})
You can also follow bellow link that may be helpful for you
https://tutorialedge.net/javascript/angularjs/removing-duplicates-from-ng-repeat/

Why is it that My Array is Undefined after Pushing an Element from an Observable

So basically, I have a web application that retrieves data from Firebase using rxjs observables.
here's my code,
initializeItems(){
this.travelList$ = this.plsdala.getTravelList()
.snapshotChanges()
.map(
changes => {
return changes.map(c=>({
key: c.payload.key, ...c.payload.val()
})).slice().reverse();//to reverse order
})
this.travelList$.subscribe(res => {
for(let i=0;i<res.length;i++){
this.ListOfitems.push (res[i].toAddress);
}
})
}
this is called from the constructor. problem here is that i cannot check if it is push successfully and if try to print in console , it wont print. why?
the element pushed is needed for filtering. heres is the code for filtter. but when i print the this.ListOfitems in console it is undefined and im wondering unto why? when the elements are initialized first
getItems(ev: any) {
console.log("awdaw");
console.log(this.ListOfitems);
if (this.ListOfitems.length>1){
console.log("otin");
let val = ev.target.value;
if (val && val.trim() != '') {
this.ListOfitems = this.ListOfitems.filter((ListOfitems) => {
return (ListOfitems.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}
}
when you are declaring list of items if you want to push into the array you need to declare it empty first like this:
ListOfitems: string[] = [];

Categories