0

In my Angular app I am pulling in some data via an asynchronous call. Then, once I have that data, I have a function (see below) that iterates over that array and gets a record_id for a passed-in corresponding stageName. I'm running into a ts error however -- there is a red squigly under stageRecords (see asterixes below), and the error is:

[ts] Type 'Observable' is not assignable to type 'any[]'.
Property 'length' is missing in type 'Observable'.

This is my code:

public async getStageIdByName(stageName)
{
    let stageRecords = [];
    **stageRecords** = await this.getAllStages();
    if (stageName && stageRecords) {
        console.log('stageRecords: ', stageRecords);
        for (let record of stageRecords) {
            if (record.stage === stageName) {
                let stageId = record._id;
                console.log(`stageId for ${stageName} is ${stageId}`);
                return stageId;
            }
        }
    }
}

What do I need to change to address this? I tried using Array.from() but this doesn't resolve the issue of this being an observable, which apparently makes this move impossible. How can I address getting an array from the response to this.getAllStages()?

UPDATE: After a suggestion I imported the toPromise() operator, and then changed my code to look like this:

public async getStageIdByName(stageName)
{
    let stageRecords = [];
    stageRecords = await this.getAllStages().toPromise();
    if (stageName && stageRecords) {
        console.log('stageRecords: ', stageRecords);
        for (let record of stageRecords) {
            if (record.stage === stageName) {
                let stageId = record._id;
                console.log(`stageId for ${stageName} is ${stageId}`);
                return stageId;
            }
        }
    }
}

This seems like the right track, however, I'm now getting this error:

Type 'Response' is not assignable to type 'any[]'.
  Property 'length' is missing in type 'Response'.

By the way, my getAllStages() function looks like this:

public getAllStages()
{
    let stageRecords;
    let recordsArray;
    let fn = response => {
        stageRecords = response.data;
        if (stageRecords) {
            recordsArray = Array.from(stageRecords);

            return recordsArray;
        }
    };

    return this.stageService.getStages((fn));
}
Muirik
  • 5,085
  • 3
  • 39
  • 71
  • Possible duplicate of [How can I \`await\` on an Rx Observable?](https://stackoverflow.com/questions/34190375/how-can-i-await-on-an-rx-observable) – peinearydevelopment Sep 06 '18 at 15:08

1 Answers1

3

Your getAllStages returns Observable, not promise, so you cannot await it.

Either you make it a promise via toPromise() method, or you subscribe to it.

This should work if you use rxjs 6 (angular 6) and if it is http request behind that, in older versions you would need to import that toPromise operator.

stageRecords = await this.getAllStages().toPromise();

In older versions of angular, you will need to import that operator like this

import 'rxjs/add/operator/toPromise';
Martin Adámek
  • 12,431
  • 5
  • 25
  • 47
  • Thanks. I did try subscribing to it, but this didn't work. But this may be because we're on Angular 2.4. I will try using `toPromise()` , as that seems to be exactly what I need here. – Muirik Sep 06 '18 at 15:12
  • 1
    Keep in mind that in older versions than angular 6, you should import that operator (something like `import 'rxjs/add/operator/toPromise';`) – Martin Adámek Sep 06 '18 at 15:13
  • @Martin_Adámek, so I made the change, and imported the toPromise operator, now I get this error: `Type 'Response' is not assignable to type 'any[]'. Property 'length' is missing in type 'Response'.` Ideas? – Muirik Sep 06 '18 at 15:41
  • So you are using angular 2, with http module (not http client module), right? If so, you need to call `json()` method on the response to get the response body. See this https://angular.io/api/http/Http#example – Martin Adámek Sep 06 '18 at 15:43
  • Their example uses angular 6 with rxjs 6, for you it will be easier. Just import `map` operator (same as with `toPromise`) and use that on the response (inside your `getAllStages` method. If you struggle with that, please add also that method implementation. – Martin Adámek Sep 06 '18 at 15:47
  • Something like `this.http.get(...).map(res => res.json())` in your `getAllStages` method. – Martin Adámek Sep 06 '18 at 15:48
  • 1
    So just add the `map` part (dont forget to import `map` operator) like this: `return this.stageService.getStages(fn).map(res => res.json());` – Martin Adámek Sep 06 '18 at 15:50