0

Im trying to fetch some data in dependecy of currently existing data. The usecase is the following: I have a json array of groups, to calculate the amount of all transactions of each group i have to do an axios.get request for each group (to request this groups i need there groupIds, existing in the groups array). But i think i stuck cause i dont really know how to iterate through a for loop asynchronously. Here is what i did:

repareTransactionAmouts: function(){
     for(var i = 0; i < this.transactionGroups.length; i++){
         var groupId = this.transactionGroups[i].groupId
         this.transactionsGroupsCount = i;
       Promise.all([this.calculateTransactionAmounts(groupId)]).then( promiseData =>  {

    this.transactionGroups[this.transactionsGroupsCount].totalAmount=promiseData[0]

     if(this.transactionsGroupsCount == this.transactionGroups.length){
       this.transactionGroups.sort(this.GetSortOrder("totalAmount"))
       this.amountsCalculated = true;
     }
    }
 }
 },

transactionsGroups is my array of filtered groups with transactions and transactionsGroupCount is a global variable to add the transactionamounts to the array position on [transactionsGroupCount]. When all groups are filled with the amout i want to sort this and set a boolean.

Next the function calculateTransactionAmounts:

    calculateTransactionAmounts: function(groupId){
return new Promise((resolve, reject) => {
  var transactions = []
  var amount = null
      axios
        .get(webServiceURL + "/groups/" + groupId, {
          headers: { Authorization: "0 " + this.authToken }
        })
        .then(response => {
            transactions = response.data.payload.transactions;


console.log("Desired Group: " + JSON.stringify(response.data.payload));
                for(let j = 0; j < transactions.length; j++){
                  amount += transactions[j].amount
                  console.log("Transactiongroup" )                                   
                  console.log(JSON.stringify
                  (this.transactionGroups[this.transactionsGroupsCount]))                                             
              resolve(amount)
            }              
        })
        .catch(e => {
          console.log("Errors get groupids: " + e);
          reject(e)
        });     
      })},

The main problem here is, that the for-loop is processed completly before the function calculateTransactionAmounts is called, so i have some calls but all with the same groupId. There is some fancy stuff happening which i cant explain why: The output "Desired Group" displays me every group i have in my array, but the "this.transactionGroups[this.transactionsGroupsCount]" outputs me allways the same group, for every iteration.

If it helps: im developing a vue2 app and need this fetched amount data to display some transaction charts

Alex
  • 132
  • 1
  • 4
  • 21
  • 1
    by the way, you do `Promise.all([this.calculateTransactionAmounts(groupId)]).then` - so, you're running `Promise.all` on a **single promise** .. just do `this.calculateTransactionAmounts(groupId).then` instead – Jaromanda X Jan 17 '18 at 23:20
  • 1
    Also, avoid the [explicit Promise construction anti-pattern](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it) - which you are guilty of in `calculateTransactionAmounts` function as `axios.get` returns a Promise, there's no need to wrap that Promise in a `new Promise` – Jaromanda X Jan 17 '18 at 23:22
  • 1
    by the way, I believe your code boils down to https://jsfiddle.net/zxk59o6c/ – Jaromanda X Jan 17 '18 at 23:44
  • @JaromandaX I just copy pasted ur snipped and all i tried within 8 hours now is resolved. Ur my personal genious :* Thank you so much! – Alex Jan 18 '18 at 00:15
  • I've added an answer, with some explanation of the changes to your code. – Jaromanda X Jan 18 '18 at 00:25

1 Answers1

1

Analysing your code, it can be greatly simplified as follows

prepareTransactionAmouts() {
    return Promise.all(this.transactionGroups.map((group, i) => 
        this.calculateTransactionAmounts(group.groupId)
        .then(promiseData => group.totalAmount = promiseData)
    )).then(results => {
        this.transactionGroups.sort(this.GetSortOrder("totalAmount"));
        this.amountsCalculated = true;
    });
},
calculateTransactionAmounts(groupId) {
    return axios.get(webServiceURL + "/groups/" + groupId, {
        headers: {
            Authorization: "0 " + this.authToken
        }
    })
    .then(response => 
            response.data.payload.transactions.reduce((total, { amount }) => total + amount, 0)
    );
}

Changes from your code include

  1. Using Promise.all on promises returned by mapping this.transactionGroups to the (Promise) result of each call to this.calculateTransactionAmounts

  2. Performing the this.transactionGroups.sort and amountsCalculated = true once all the above promises have resolved - rather than tracking the index, since this does not account for asynchronism anyway

  3. Removing the new Promsie anti pattern in calculateTransactionAmounts

  4. Simplifying the amount += transactions[j].amount by using Array#reduce

  5. In general, using modern (ES2015+) javascript where applicable

Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • thank you so much also for explaining. I must say im pretty new to Javascript, have to do this for a study project but trying to improve further :) – Alex Jan 18 '18 at 00:40