3

My backend API http://localhost:8300/api/picture returns a string and I have tried following approaches: ( getpicture is called on button click)

Approach 1:

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-auth-success',
  templateUrl: './auth-success.component.html',
  styleUrls: ['./auth-success.component.scss']
})
export class AuthSuccessComponent implements OnInit {

  showImg: boolean = false;
  imgUrl: string = "";

  constructor(private http: HttpClient) { }

  ngOnInit() {    

  }
    getPicture(){
        this.http.get("http://localhost:8300/api/picture",{ observe: 'response' })                                                   
                .subscribe(
                  res => { 
                    console.log(res);                   
                    this.onSuccess(res);
                  }, error => {
                          console.error("Some error while calling backed");
                        });
      }

      onSuccess(data: any){
        this.imgUrl = data;
        this.showImg = true;
      }
}

And HTML:

<div>
 <button (click)="getPicture()">Google Picture</button><br><hr><hr>

 <img [src]="imgUrl" *ngIf="showImg">
 </div>

Output:

"Some error while calling backed" found (i.e. error is printed)

Approach 2:

 getPicture(){
        this.http.get("http://localhost:8300/api/picture")
                .map((res : Response)=> {
                  console.log(res); // correct value printed if below line is commented
                  this.imgUrl = res.text(); // compiler gives error at this line
                })                                                   
                .subscribe();

      }

Output: I get compiler error:

Type Promise<string> is not assignable to type 'string'.

What am I missing?

EDIT: I have removed the custom error message that was getting printed

"Image not found"

with console.error(error) as it was creating a confusion that my backend is returning this error. The error message printed is:

e {headers: t, status: 200, statusText: "OK", url: "http://localhost:8300/api/picture", ok: false, …} error : {error: SyntaxError: Unexpected token h in JSON at position 0 at JSON.parse () at XMLHttp…, text: "https://lh3.googleusercontent.com/-46Nb-WbneSU/AAAAAAAAAAI/AAAAAAAAAAc/V7Pz0b9mxdw/photo.jpg"} headers : t {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ} message : "Http failure during parsing for http://localhost:8300/api/picture" name : "HttpErrorResponse" ok : false status : 200 statusText : "OK" url : "http://localhost:8300/api/picture"

3
  • Can you paste a sample response from API here? Commented Feb 23, 2018 at 8:23
  • 1
    @theLearner, "map" it's used to transform the response, not to make a call function (you can use "do"). You get the response in "subscribe", so your first aproach is the correct. Sure you use HttpClient, try to write console.log(error) to see the error Commented Feb 23, 2018 at 8:37
  • @Eliseo any idea about the error message: Type Promise<string> is not assignable to type 'string'. Commented Feb 23, 2018 at 9:08

1 Answer 1

2

As explained in this answer, Http was inspired by Fetch API and has classes of same names, though they aren't compatible, because Http uses observables, and Fetch API uses promises.

The implication is that if Response wasn't imported, global Response will be used. Since Response is used here only as a type, the problem affects types only. There should be:

import { Response } from '@angular/http';

This doesn't apply to HttpClient. The main difference in the code that uses HttpClient is that response negotiation is performed with observe and responseType options, and .map((res) => res.text()) line should be omitted.

Approach 1 uses observe: 'response' which isn't needed here, but doesn't set responseType which defaults to json and results in JSON parse error. Approach 2 uses Http API, while http is HttpClient.

map isn't a proper place for side effects. Dummy subscribe() indicates that an observable is misused here. If there's no benefit from using observables, a promise may be more convenient option:

async getPicture(){
  try {
    this.imgUrl = await this.httpClient.get("http://localhost:8300/api/picture", { responseType: 'text' })
    .toPromise();

    this.showImg = true;
  } catch (e) {
    ...
  }
}

This isn't relevant to original problem, Image not found. Backend API responds with an error. This has nothing to do with Angular and should be fixed, depending on the backend.

Sign up to request clarification or add additional context in comments.

5 Comments

I have put a breakpoint at backend and backend is returning the correct string always i.e. in both the approaches. Also as I mentioned in my question that if I use Approach 2, and print the response, the response returned by backend is printed correctly(the error comes when I try to assign it to my local variable). Image not found is printed in Approach 1 and angular is printing it because in console.error I have given that message.
I have changed the error message as it was creating confusion.
It doesn't really matter what backend debugging says. It matters what the browser receives. You can check this in dev tools network tab. There can be countless reasons why there may be an error, and you're the only person who can output error and check what's wrong. Approach 1 won't work correctly because there's no res.text(), but it won't cause this error. Any way, the question covers what's wrong with Angular code. The rest depends on your backend. Hope this helps.
Notice that the answer assumes that you use Http. This is what the code in the question implies. This won't be true for HttpClient
This is a very silly mistake on my part. I am using HttpClient. I should have posted the complete file. Edited the question now.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.