1

I want to fetch data from an API which works like a charm but i am struggling with filtering a single Report by a given id from an "Observable".

Here are some snippets:

getAllReports(): Observable<Report[]> {
    return this.http.get(this.reportUrl)
        .map(res => res.json().results);
}

getReports(): void {
    this.reportService.getAllReports()
        .subscribe(
            reports => this.reports = reports,
            error => console.log(error)
        );
}

getSingleReport(id: number): Promise<Report> {
    return this.getAllReports()
        .then(reports => reports.find(report => report.id === id));
        // ^ "Property 'then' does not exist on type 'Observable<Report[]>'"
}

getSingleReport1(id: number): Promise<Report> {
    this.getAllReports()
        .subscribe(
            reports => this.reports = reports,
            error => console.log(error)
        );
    return this.reports.find(report => report.id === id);
    // ^ "Type 'Report' is not assignable to type 'Promise<Report>'"
}
  1. getAllReports() is responsible for the communication with the API and returns an Ovserable
  2. getReports() inserts the results from the API call in a reports: Report[] aray
  3. getSingleReport() should return a Promise<Report> with the given Observable<Report[]>
  4. getSingleReport1() is my first try fixing the problem which unfortunately also doesn't work

Of course i know where the problems in 3 & 4 are but in don't know how to solve them.

How can i accomplish a conversation from Report or Observable<Report[]> to Promise<Report>.

Any help is highly appreciated.

Thank you.

2 Answers2

0

Use toPromise operator like this:

getSingleReport(id: number): Promise<Report> {
    return this.getAllReports()
        .subscribe(reports => reports.find(report => report.id === id)).toPromise();
}
Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • With this code i am getting another error (even after importing `rxjs/add/operator/toPromise`) `Property 'toPromise' does not exist on type 'Subscription'.` –  Jul 12 '17 at 10:10
  • something is wrong with your setup then, try restarting the app. it should work – Max Koretskyi Jul 12 '17 at 10:16
  • I restarted and -compiled everything but its still not working. Are you sure the code is correct? [My Class](https://pastebin.com/raw/KnbjZfXR) –  Jul 12 '17 at 10:36
  • _Property 'toPromise' does not exist on type 'Subscription'_ - this is compile time warning, how does it work in production? do you use ng-cli? yes, the code should work – Max Koretskyi Jul 12 '17 at 10:53
  • I don't know what you mean but when starting my application (created with ng-cli by `npm new [NAME]`) with `ng serve -o` in developement mode i get this exact message on the `Failed to compile screen.`: `D:/***/***/***/Berichtsprogramm-UI/src/app/report.service.ts (27,83): Property 'toPromise' does not exist on type 'Subscription'.` –  Jul 12 '17 at 11:29
  • I just added `import 'rxjs/add/operator/toPromise';` inside the file and ng-cli works OK – Max Koretskyi Jul 12 '17 at 12:09
  • No. I have no idea where the mistake could be. I am useed to Java and other C languages so it could be that i have a major mistake somewhere else. The Order of imports is not relevant, is it? –  Jul 12 '17 at 13:27
  • sorry, can't help then, the code is working I'm sure and this is the correct solution – Max Koretskyi Jul 12 '17 at 13:29
  • Well thats kinda wierd but HUGE thanks anyway :D If i find the problem and the proper solution i'll post it here. –  Jul 13 '17 at 12:08
  • @TheSecret, great, you can then upvote or accept my answer :) – Max Koretskyi Jul 13 '17 at 12:30
  • I still didn't find a final solution BUT i suspect that anything is outdated a.e the typescript compiler because of this i reinstalled Angular cli but im not even sure if this also updated the compilers. In the readme.md it says `This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.1.1.` is it posible that this is causing an error ? –  Jul 17 '17 at 06:36
  • no, you have to create a plunker or some github repo with minimal reproduction demo for me to see what's going on there – Max Koretskyi Jul 17 '17 at 06:43
0

So i still didn't find a solution but i came up with a workaround i'll post here. I changed getSingleReport(id: number): Promise<Report> to getSingleReport(id: number): Report.

getSingleReport(id: number): Report {
    this.getAllReports()
        .subscribe(
            reports => this.reports = reports,
            error => console.log(error)
        );
    return this.reports.find(report => report.id === id);
}

This works but is still throwing the error TypeError: Cannot read property 'find' of undefined. I'll probably fix it later today.

UPDATE:

I got it perfectly working now but i decided to do it without a Promise.

report-detail.component.ts:
getReport(id: number) {
    this.reportService.getSingleReport(id)
        .subscribe(
            report => this.report = report,
            error => console.log(error)
        );
}

report.service.ts:
getSingleReport(id: number): Observable<Report> {
    const apiUrl = 'http://localhost:8080/Berichtsprogramm-API/getReport?api_key={TEMPORARY_APIKEY}&id=' + id;
    return this.http.get(apiUrl)
            .map(res => res.json());
}

This works for my case and finally i can be happy again.

  • This answer is wrong because you are trying to traverse a field which you defined asynchronously. If you want to conver observable to promise do this: `getAllReports() { return this.http.get(this.reportUrl) .map(res => res.json().results).toPromise(); }` – eko Jul 20 '17 at 08:01
  • WOW ... the whole conversation above covers the fact that `.toPromise() `doesn't work for me. If you could either suggest a better solution or tell me why `.toPromise()` doesn't work for me i'd be very greatful. –  Jul 20 '17 at 08:10
  • No promises work for you. You just don't know how to handle async operations :-) I'll try to explain. When you use `getSingleReport1` somewhere in your code, what happens is this: you make a `http.get` request and http requests are async. Think of it like you are making a phone call. But you don't know when the response will arrive. When it arrives, it will fall into the subscribe/then block of the call. So this block will be executed when the data arrives. Check: https://stackoverflow.com/questions/43055706/how-do-i-return-the-response-from-an-observable-http-async-call-in-angular2. – eko Jul 20 '17 at 08:15
  • Well, i know what sync and async operations are and usually how to handle them (not the case in Angular) but the big problem is that i was getting an seemingly unfixable error being `Property 'toPromise' does not exist on type 'Subscription'.` although i imported everything necessary. Or is this my mistake that i tried to use `.toPromise()` at the wrong place. –  Jul 20 '17 at 08:36
  • Yes you can't use `.toPromise()` on subscriptions. Check my first comment. You should use it after the map function. – eko Jul 20 '17 at 09:56
  • @echonax What do you say? Do you think this is a correct solution? I'm really curious. I have updated the answer. –  Jul 21 '17 at 13:16
  • @echonax, `toPromise` should have solved the problem as I showed, the OP can't seem to understand the basics... – Max Koretskyi Jul 21 '17 at 14:29
  • @Maximus Ah I didn't see your answer sir. Since it's an old post when OP gave an answer it fell into the active tab and I just looked that one :-) I didn't know you can convert subscriptions to promises tho. – eko Jul 22 '17 at 06:08