0

I have code:

data.service.ts

  getDataById(id: number): Observable<Model> {
    return this.httpClient.get<Model>(this.api + 'data?id=' + `${id}`);
  }

data.component.ts

firstFunc(id) {
 this.secoundFunc(id);
 console.log('res from service', this.data); // log undefined
 //do something with this.data
}

secoundFunc(id) {
 this.dataService.getDataById(id).subscribe(res=> {
 this.data = res;
})
}

How to wait for the service to be executed? And then continue executing the rest of the code. I understand that http request is done as asynchronous operation. I've used, promises, async/await, setTimeout, but none of this helps.

  • _I've used, promises, async/await, setTimeout_....Can you share it in the post? – Jai Aug 27 '20 at 09:27

3 Answers3

0

There is no way to turn asynchronous variable to be synchronous. The only thing you could do is to move all the statements depending on the async variable inside the subscription.

firstFunc(id) {
  this.dataService.getDataById(id).subscribe(res=> {
    this.data = res;
    console.log('res from service', this.data);
    //do something with this.data
  });
}

If you need to use this.data in multiple places and do not wish to trigger the HTTP call each time, you could cache the response in the service using RxJS ReplaySubject and use it in the component.

Service

export class DataService {
  private cachedSource = new ReplaySubject<any>(1);      // <-- cache last emitted value
  public cached$ = this.cachedSource.asObservable();

  getDataById(id: number): Observable<Model> {
    return this.httpClient.get<Model>(this.api + 'data?id=' + `${id}`).pipe(
      tap(res => this.cachedSource.next(res))
    );
  }
}

Component

export class SampleClass implements OnDestroy {
  complete$ = new Subject<any>();

  firstFunc(id) {
    this.getDataById(id);
    this.dataService.cached$.pipe(takeUntil(this.complete$)).subscribe(
      res => {
        this.data = res;
        console.log('res from service', this.data);
        //do something with this.data
      }
    );
  }

  someOtherFunction() {
    this.dataService.cached$.pipe(take(1)).subscribe(
      res => {          // <-- will emit the last value from the HTTP call
        console.log('res from service', res);
        //do something with `res`
      }
    );
  }

  getDataById(id: number) {
    this.dataService.getDataById(id).subscribe();     // <-- pushes response to `this.dataService.cached$`
  }

  ngOnDestroy() {
    this.complete$.next();        // <-- close open subscriptions
  }
}
ruth
  • 29,535
  • 4
  • 30
  • 57
  • Thanks. I know this but I want to know whether this problem can be solved on another way. Thanks for answer. – Dragan Krivokuća Aug 27 '20 at 09:27
  • @DraganKrivokuća: You need to use async variables anyway. I've included a basic caching method in the answer if you don't wish to trigger the HTTP request for each usage of it's response in the component. – ruth Aug 27 '20 at 09:39
  • Yes, this can help. But I need check the data by id, and I must trigger http request every time to check if there have been any changes. – Dragan Krivokuća Aug 27 '20 at 10:13
  • @DraganKrivokuća: In that case, you can trigger the HTTP function wherever the latest data is required. – ruth Aug 27 '20 at 10:48
0

You can do operations on data in subscribe.

    firstFunc(id) {
     this.secoundFunc(id);
    }
    
    secoundFunc(id) {
     this.dataService.getDataById(id).subscribe(res=> {
     this.data = res;
     console.log('res from service', this.data); 
     //do something with this.data
    })
    }
Akhil Naidu
  • 789
  • 1
  • 4
  • 16
0

Maybe you could try callback!

firstFunc(id) {
 this.secoundFunc(id, () => {
   console.log('res from service', this.data); 
   //do something with this.data
 });
}

secoundFunc(id,callback) {
 this.dataService.getDataById(id).subscribe(res=> {
   this.data = res;
   callback && callback();
 })
}

Or try async function

   async firstFunc(id) {
    const result = await this.secoundFunc(id).toPromise();
    // if (result ???)
    // do sth
   }
   
   secoundFunc(id) {
    return this.dataService.getDataById(id)
   }
fbfatboy
  • 371
  • 1
  • 6