Skip to content
Advertisement

TypeScript – waiting for nested for loops to complete

I have two for loops, one nested inside the other. The first loop makes an API call. It will execute for how ever many IDs are selected by the user. I do not have the ability pass more than one ID at a time to the API. The nested loop will run for each object returned by the API and add the data to an array. My end goal is to have all data in a single array, and to pass that array to a child component using @Input(). I have researched and attempted to do this using a Promise, but something is still not quite right. I would like ngOnChanges() in the child component to only execute once all of the data has been returned – aka both for loops have completed execution. This is what I have done:

Parent Component:

  getData() {
    let temp: MyObjectType[] = [];
    let allDataToSend: MyObjectType[] = [];

    return new Promise<MyObjectType[]>((resolve, reject) => {

      for (let i = 0; i < this.userIdSelections.length; i++) {
        this.dataService.getData(this.userIdSelections[i])
          .subscribe(results => temp = results,
            error => {
              this.getRequestResult = <any>error;
            },
            () => {

                for (let j = 0; j < temp.length; j++) {
                  allDataToSend.push({
                    Property1: temp[j].Property1,
                    Property2: temp[j].Property2,
                    Property3: temp[j].Property3,
                    Property4: temp[j].Property4,
                  });
                
              }
            }
          );
      }
      resolve(allDataToSend);
    });
  }

  finalResults() {
    this.getData().then(response => {
      this.FinalObjectSendToChild = response;
    })
  }

Parent Template:

<button mat-flat-button color="primary" (click)="finalResults()">Search</button>

<app-child [finalData]="FinalObjectSendToChild"></app-child>

Child Component:

export class ChildComponent implements OnChanges {
  @Input() finalData: MyObjectType[];
  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;
  public tableColumns = ['Property1', 'Property2', 'Property3', 'Property4'];
  public tableData: any

  constructor() { }

  ngOnChanges(changes: SimpleChanges) {
    if (changes.finalData) this.createTable();
  }

  createTable() {
    console.log(this.finalData); // this will show all of the data the way I would expect
    console.log(this.finalData.length); // however, this always returns 0
    // the table created is blank...
    this.tableData = new MatTableDataSource(this.finalData);
    this.tableData.sort = this.sort;
    this.tableData.paginator = this.paginator;
  }

Advertisement

Answer

You can use Promise.All:

(...)
for (let i = 0; i < this.userIdSelections.length; i++) { 
  arrayPromises.push(this.dataService.getData(this.userIdSelections[i]).toPromise());
}

Promise.all(arrayPromises).then((values) => {
  const allDataToSend = [];
  for(let value of values) {
    for (let j = 0; j < value.length; j++) {
        allDataToSend.push({
          Property1: value[j].Property1,
          Property2: value[j].Property2,
          Property3: value[j].Property3,
          Property4: value[j].Property4,
        });
    }
  }
  resolve(allDataToSend);
});
(...)
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement