Sam Willis
Sam Willis

Reputation: 4211

Angular service method to return data after async requests complete

I have a component which is making a call to a service to get data; initAllData().

This method then performs two requests for some json and uses forkJoin to manipulate the data once it has returned. Once all the data has been manipulated, I want to return the new data (this.results) in the method so that I receive it in my component.

Here is my method:

initAllData() {

// Get player data
this.players = this.getPlayersData();

// Get results data
this.scores = this.getResultsData();

forkJoin([this.players, this.scores]).subscribe(data => {

  // data[0] is the players
  // data[1] is the scores
  let playersArray = data[0].Players;
  let scoresArray = data[1].Results;

  // Populate the results array by merging each player with their scores based on the PlayerId
  this.results = playersArray.map(player => {
      return Object.assign(
        {}, 
        player, 
        scoresArray.find(score => score.PlayerId === player.PlayerId),
        {"Position": null}
      );
  });

  // Sort the results array from highest TotalScore to lowest
  this.results.sort((a, b) => b.TotalScore - a.TotalScore);

  // Add a position value to the results
  this.results.forEach((item, index) => {
    item.Position = index + 1;
  });
  console.log(this.results)

}); 

return this.results // this is undefined until forkJoin completes :(

}

Currently it is returning null as it runs before the forkJoin function has completed populating the property.

Upvotes: 0

Views: 659

Answers (3)

Shruti Agrawal
Shruti Agrawal

Reputation: 366

return using promise

initAllData() {
// Get player data
  this.players = this.getPlayersData();
  // Get results data
  this.scores = this.getResultsData();
  return new Promise((res,rej)=>
  {
    forkJoin([this.players, this.scores]).subscribe(data => {

      // data[0] is the players
      // data[1] is the scores
      let playersArray = data[0].Players;
      let scoresArray = data[1].Results;

      // Populate the results array by merging each player with their scores based on the PlayerId
      this.results = playersArray.map(player => {
          return Object.assign(
            {}, 
            player, 
            scoresArray.find(score => score.PlayerId === player.PlayerId),
            {"Position": null}
          );
      });

      // Sort the results array from highest TotalScore to lowest
      this.results.sort((a, b) => b.TotalScore - a.TotalScore);

      // Add a position value to the results
      this.results.forEach((item, index) => {
        item.Position = index + 1;
      });
      console.log(this.results)
      res(this.results)
    });
  });
}

Call As:-

initAllData().then(data=>console.log(data));

Upvotes: 0

mbojko
mbojko

Reputation: 14689

You need to return an observable. Don't subscribe in the initAllData, instead do

return forkJoin([this.players, this.scores]).pipe(
    map(([players, scores]) => {

// Do the assignments here, and return results in the end:
        return this.results;
    }));
//...

Now, the initAllData's consumer should:

this.initAllData().subscribe(results => // now he has results

Upvotes: 3

user3278175
user3278175

Reputation: 7

Return forkJoin promise from service. forkJoin promise should return the combined result of all data (this.results in your case).

Upvotes: 0

Related Questions