codewarrior
codewarrior

Reputation: 61

Angular 5+ wait for service that returns a promise

I have a service call that returns a promise, but when I try to set the return type as promise I'm having trouble using it in the caller function due to the type not being recognized, so it won't compile.

So I have tried using the below method, but I run into a timing issue (code executes before call finishes)

  private getSomeData(): DataObjectArray[] {
    return this.myService.something().map((response: Response) => {
      return response.children;
    });
  }

  public compileData(): DifferentDataArray[] {

   // get some stuff from a config, then make service call
    let someData = this.getSomeData();

    /* If I have a promise returned, someData errors saying not an array type */
    for (let oneData of someData){
      /* loop through config data + service data making a return object array */
   }
    return this.dataCollection;
  }

Upvotes: 1

Views: 1848

Answers (3)

bgraham
bgraham

Reputation: 1997

I recommend in Angular you try to keep things as observables. Its nice to be consistent, instead of flipping back and forth between observables and promises.

I'm not super clear if myService.something() returns a promise or an observable. If observable:

  private getSomeData(): Observable<<DataObjectArray[]> {
    return this.myService.something().pipe(
       map(response => response.children)
    );
  }

if its a promise very similar but:

    private getSomeData(): Observable<<DataObjectArray[]> {
      return fromPromise(this.myService.something()).pipe(
       map(response => response.children)
      );
    }

Then:

  public compileData(): Observable<DifferentDataArray[]> {

   // get some stuff from a config, then make service call
    return this.getSomeData().pipe(
       map(someData => {
           /* If I have a promise returned, someData errors saying not an array type */
           var dataCollection = [];
           for (let oneData of someData){
            /* loop through config data + service data making a return object array */
                 // should dataCollection.push(changedData);
            }
            return dataCollection;
       });
    );

  }

Finally to consume somewhere else:

     this.compileData().subscribe(compiledData => {
         // do something with the compiled data
     });

Notes: The pipe operator is pretty powerful. It takes an observable, and lets you do some work on it before returning it. In this case, I used the map operator, because you are just changing the shape of the return a little bit. At the end of the chain, you must always subscribe to an observable to get the data back (per the last black in my example)

Upvotes: 2

Stefan
Stefan

Reputation: 14863

You can use the new Javascript keywords async and await

First make getSomeDataasync, which also requires it to return a promise:

  private async getSomeData(): Promise<DataObjectArray[]> {
    return this.myService.something().map((response: Response) => {
      return response.children;
    });
  }

then await the function in compileData:

let someData = await this.getSomeData();

However, this means that compileData because it returns a result, has to be async too. This means you need to add the async keyword and change the type to Promise<DifferentDataArray[]>.

In case you don't care about your result, you can call a async function without await, so you also don't have to wait for the result and it is handled in the background. If you rely on the result, you have to await it. In this case, other parts of your application can continue! Anyway, if you are designing an async application you have to think about what happens when anyway.

Your full compileData function:

 public async compileData(): Promise<DifferentDataArray[]> {

   // get some stuff from a config, then make service call
    let someData = await this.getSomeData();

    /* If I have a promise returned, someData errors saying not an array type */
    for (let oneData of someData){
      /* loop through config data + service data making a return object array */
   }
    return this.dataCollection;
  }


  public compileData(): DifferentDataArray[] {

   // get some stuff from a config, then make service call
    let someData = this.getSomeData();

    /* If I have a promise returned, someData errors saying not an array type */
    for (let oneData of someData){
      /* loop through config data + service data making a return object array */
   }
    return this.dataCollection;
  }

Upvotes: 1

user4676340
user4676340

Reputation:

  private getSomeData(): DataObjectArray[] {
    return this.myService.something().map((response: Response) => {
      return response.children;
    });
  }

Should be

  private getSomeData(): Promise<DataObjectArray[]> {
    return this.myService.something().map((response: Response) => {
      return response.children;
    });
  }

Upvotes: 0

Related Questions