I'm trying to loop over a list of views, and for each view retrieve a list of objects associated with that view, using a service call. Each view is being assigned the result of the last call to the function, instead of the result of the function call with its parameters.
Debugging output statements in the service layer method show that it is fetching the correct values. Adding a call to the method after the loop updates the views to use the results of that call.
I'm experienced programming in Angular2 and I've never come across this issue before, but I can't see what I'm doing differently. It seems the view property is being assigned the function rather than the function result.
Searching the issue suggests it's a closure issue, but I couldn't get any of the traditional solutions for this to work.
Here's what I have:
views.forEach((view: PeriodSummaryView) => {
view.CategorySummaries = API.getCategorySummariesByPeriod(view.Period, new Date()); // every view is given the result of the last evaluation of this function
view.TotalSpent = this.sumAmounts('Spent', view.CategorySummaries);
view.TotalBudgeted = this.sumAmounts('Budgeted', view.CategorySummaries);
});
and the API layer:
export default class API {
static getCategorySummariesByPeriod(filterPeriod: Period, filterDate: Date): CategorySummary[] {
var self = this;
let summaries: CategorySummary[] = Categories.slice();
summaries.forEach((category: CategorySummary) => {
category.Spent = Expenses.filter(function (e) {
return e.CategoryId == category.CategoryId
&& self.isDateInPeriod(filterPeriod, filterDate, e.Date)
}).reduce(function (acc, e) {
return acc + e.Cost;
}, 0);
});
return summaries;
}
}
Expected: Each view should have its own list of CategorySummaries, fetched from the API method using its parameters.
Actual: All views have the same list; the result from the last call to the API method.
Note: TotalSpent and TotalBudgeted are being calculated correctly.
Simply create a list prior to the for loop, and then append to that list instead of printing. Show activity on this post. Just declare an empty list and append results into that list.
The return statement is useful because it saves time and makes the program run faster by returning the output of method without executing unnecessary code and loops. It is good practice to always have a return statement after the for/while loop in case the return statement inside the for/while loop is never executed.
You can use a for loop to create a list of elements in three steps: Instantiate an empty list. Loop over an iterable or range of elements. Append each element to the end of the list.
Using Python for loop to iterate over a list. In this syntax, the for loop statement assigns an individual element of the list to the item variable in each iteration. Inside the body of the loop, you can manipulate each list element individually.
The forEach function don't modify the original array. You must to create a new empty array and push each calculed item to the new array and return it.
export default class API {
static getCategorySummariesByPeriod(filterPeriod: Period, filterDate: Date): CategorySummary[] {
var self = this;
let summaries: CategorySummary[] = Categories.slice();
let new_arr = [];
summaries.forEach((category: CategorySummary) => {
category.Spent = Expenses.filter(function (e) {
return e.CategoryId == category.CategoryId
&& self.isDateInPeriod(filterPeriod, filterDate, e.Date)
}).reduce(function (acc, e) {
return acc + e.Cost;
}, 0);
new_arr.push(category);
});
return new_arr;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With