2

I'm using Angular 6 and my database is Firebase. Now I try to show each of the room's names according to its building. For example:

Building A
Room 1
Room 2
Building B
Room 1
Room 2

But every time I try, it will show all the building names first, and only then it will show the room's names. This is what I got for now:

Building A
Building B
Room 1
Room 2

I find out this happens because forEach keeps skipping the subscribe function.

I have attempted to use promise and await, but it doesn't work. Maybe because I use it in a wrong way? I'm not so sure how to use promise in a correct way.

async loadData(){
    this.navigationService.user
        .subscribe( user => {
        console.log(user);
        this.user = user;
        this.navigationService.getBuildings(this.user.orgId)
            .subscribe( building => {
            this.navMasterBuilding = [];
            this.buildings = building;
            this.buildings.forEach( async building2 => {
                this.completeBuildingId = building2.completeBuildingId;
                this.buildingName = building2.buildingName;
                console.log(building2.buildingName);
                await new Promise ((resolve, reject) => { 
                    this.navigationService.getLocation(this.user.orgId, this.completeBuildingId)
                    .subscribe(location => {
                    console.log('room' + location);
                    this.navMasterLocation = [];
                    });
                    resolve();
                });   
            });
        });
    });
}

I have try to delay it by using setTimeout, but it still does't work.

Alif Fitri
  • 23
  • 1
  • 5
  • Please add your code to the question not just a photo of your code. – Tobias Wilfert Dec 24 '18 at 09:56
  • 1
    https://stackoverflow.com/questions/45498873/add-a-delay-after-executing-each-iteration-with-foreach-loop[enter link description here](https://stackoverflow.com/questions/45498873/add-a-delay-after-executing-each-iteration-with-foreach-loop) – Dipen Desai Dec 24 '18 at 09:57
  • Possible duplicate of [Add a delay after executing each iteration with forEach loop](https://stackoverflow.com/questions/45498873/add-a-delay-after-executing-each-iteration-with-foreach-loop) – Einar Ólafsson Dec 24 '18 at 10:03
  • 1
    Tried `resolve();` under the inner subscription? – Ashish Ranjan Dec 24 '18 at 10:03
  • I have tried `resolve();` under the inner subscription, but it still does't work. Thanks for the suggestion. – Alif Fitri Dec 24 '18 at 10:18
  • Try something like this me too have the same problem inside foreach and this is the solution i got https://stackblitz.com/edit/flatternstructure-rikbfs – Maniraj Murugan Dec 24 '18 at 10:43

1 Answers1

10

Array.forEach only works with synchronous functions. Change it to using the for...of syntax which does work. Next to that you resolve the Promise before the call to getLocation finished and the code in subscribe ran. Change the code to call resolve within the getLocation.subscribe.

for(const building2 of buildings) {
    console.log(building2.buildingName);
    await new Promise ((resolve, reject) => { 
        this.navigationService.getLocation(this.user.orgId, this.completeBuildingId)
            .subscribe(location => {
                console.log('room' + location);
                this.navMasterLocation = [];

                resolve();
             });                    
    });   
}

Note that it can be simplified to:

for(const building2 of buildings) {
    console.log(building2.buildingName);
    const location = await this.navigationService.getLocation(this.user.orgId, this.completeBuildingId).toPromise();
    console.log('room' + location);
    this.navMasterLocation = [];             
}

Also do note that I'm not quite sure why you use this.completeBuildingId instead of a local variable. Given that it gets overwritten in each iteration this seems a bit useless to me.

David Walschots
  • 12,279
  • 5
  • 36
  • 59
  • 1
    It work!!! Thanks David Walschots.. You just solved my problem.. By using `for ... of` and move the resolve into inner subscribe it really works.. Thank you very much! – Alif Fitri Dec 26 '18 at 02:32