john44
john44

Reputation: 23

How can i await the result from my method in my service?

I have this method in my service.

get trucks() {
    if (!this.cache$) {
      this.cache$ = this.requestAvailableTrucks().pipe(
        shareReplay(CACHE_SIZE)
      );
    }
    return this.cache$;
  }

  private requestAvailableTrucks() : Observable<Array<any>> {
    return this.http.get<any>(API_ENDPOINT_TRUCKS).pipe(
      map(response => response.value)
    );
  }

In my app component I need to initialized my property as the result from the requestAvailableTrucks call. And after that I need to do some logic depending on the result that came from the backend. But the problem is that I don't know how can I await this method.

When I try

ngOnInit() {
   this.locations = this.truckService.trucks;
    ... The other logic ...
}

the other logic don't wait for the method in my service to end.

The only think that can be done is the approach with subscribe, and to put the code there but I need to have my logic in my service and call it from my ts.file like this

Upvotes: 2

Views: 111

Answers (3)

shenghua lian
shenghua lian

Reputation: 149

If you want to use await, an easy way is to convert observable to be promise.

async ngOnInit() {
  this.trucks = await this.truckService.trucks.toPromise();
  // other logics
}

You can actually convert every observable api call to be promise, then you will be able to forget everything about stream. Just think in regular promise ways.

For a more reactive way:

  1. For the service, I do not thing you need to wrap the logic int a get:
class TruckService {
  trucks$ = this.requestAvailableTrucks().pipe(
    shareReplay(CACHE_SIZE)
  );

  requestAvailableTrucks() {...}
}
  1. Then you can just call it in the component, and take advantage of async pipe. The code would be like:
tracks$ = this.truckService.tracks$;
ngOnInit() {....}

// TEMPLATE
{{tracks$ | async}}

Upvotes: 0

Brajendra Swain
Brajendra Swain

Reputation: 355

you can simply use subscribe so that it will wait for the response.


    ngOnInit() {
       this.truckService.trucks.subscribe(trucks => {
          this.locations = trucks;
       });
    }

Upvotes: 1

BizzyBob
BizzyBob

Reputation: 14750

You can use the .pipe() method on an observable stream to modify the values as they come through. There are various pipeable operators that allow you to transform the stream. In your case, it looks like you are trying to turn a stream of "trucks array" into a stream of "location array". In that case, using the map() operator, something like this would work:

ngOnInit() {
   this.locations = this.truckService.trucks.pipe(
      map(trucks => trucks.map(t => t.location))
   );
}

You aren't awaiting per se, but rather transforming the values as they come through. Also, you don't need to subscribe here, but you could if you really needed to. Usually you can use the async pipe in the template like this:

<h1>Truck Locations</h1>
<ul>
  <li *ngFor="let location of locations | async">
    {{ location }}
  </li>
</ul>

If you needed to do some side effect type stuff in your "other logic", you may utilize the tap operator inside the pipe() as well.

ngOnInit() {
   this.locations = this.truckService.trucks.pipe(
      map(trucks => trucks.map(t => t.location)),
      tap(() => this.isLoading = false)
   );
}

Upvotes: 0

Related Questions