2

I am trying to retrieve information from an Observable Object. but I can't figure out how to do it properly. such as this for example, Dog API

it should return a JSON object

{
    "message": "https://images.dog.ceo/breeds/setter-english/n02100735_10064.jpg",
    "status": "success"
}

for such, I have a service function

  getRandomImage(): Observable<Random> {
    return this.client.get<Random>(`https://dog.ceo/api/breeds/image/random`)
  }

however when I try to render it on HTML

<div>
  <p *ngIf=" random$ | async">{{ random$.message }}</p>
</div>

I get error message

Property 'message' does not exist on type 'Observable<Random>'

also, can someone please explain to me in simple terms what this function does

getListFacts(length: number, limit: number) : Observable<facts[]> {
    return this.client
        .get<{ data: facts[] }>(`https://catfact.ninja/factsmax_length=${length}&limit=${limit}`)
        .pipe(map(({ data }) => data));
}

Like, I tell it to return Observable of Array of Facts, with a get request that should return an object with contains an array of facts named data, then what does the pipe map do ?

Thank you

I am trying to use Observables with Async Pipe for Rending. but I can't quite understand how to properly write observable retrieval functions for proper rendering

1 Answers1

3

The main problem is that you are accessing the observable random$ directly, when in fact you want to access the object emitted by that observable. In order to achieve what you want, you can add as randomImage in your html-code and then access randomImage.

I created a working example:

First the TS-File:

random$: Observable<RandomImage>;

constructor(private client: HttpClient) {
    this.random$ = this.client.get<RandomImage>(`https://dog.ceo/api/breeds/image/random`);
}

Then the HTML-Code:

<p *ngIf="random$ | async as randomImage">{{ randomImage.message }}</p>

Regarding your question about the map-operator

The following code retrieves the data array wrapped in an object. You then use the map operator to extract the array from the object, so that ultimately only the array without the wrapper object is returned:

getListFacts(length: number, limit: number) : Observable<facts[]> {
    return this.client
        .get<{ data: facts[] }>(`https://catfact.ninja/factsmax_length=${length}&limit=${limit}`)
        .pipe(map(({ data }) => data));
}
kellermat
  • 2,859
  • 2
  • 4
  • 21
  • OK, 1 more question please; Why in the getListFacts example, I could render the information without doing the "async as X"

    {{ fact.fact }}

    – Mamdouh Morad Dec 03 '22 at 19:52
  • 1
    When you write `*ngFor="let fact of facts$ | async"` then `facts$ | async` is executed before the loop even starts. The `of` in `let fact of` refers to the whole term `facts$ | async` and not just to `facts$`. In your previous example you directly referred to the observable `random$` by writing `{{ random$.message }}`. Therefore your previous example was a different case. – kellermat Dec 03 '22 at 20:03
  • 1
    I suggest to put brackets around `facts$ | async` in order to make more clear what happens in your code: `

    {{ fact.fact }}

    `
    – kellermat Dec 03 '22 at 20:11
  • sorry but I am stuck once again. now I am trying to use Football API [API](https://www.api-football.com/documentation-v3) this end point for example [ENDPOINT](https://v3.football.api-sports.io/players?search=Ronaldo&team=541) It should return a response array with player object and statistics object inside. I wrote this HTML-Code `

    {{player.name}}

    `
    – Mamdouh Morad Dec 05 '22 at 16:50
  • TS-Code `getPlayer(){ return this.client .get<{response : any}>( `https://v3.football.api-sports.io/players?`, { headers: { 'x-rapidapi-key': API KEY }, params : {search :'Ronaldo', team : 541}} ) .pipe(map(({ response }) => response['player'])) }` – Mamdouh Morad Dec 05 '22 at 16:51
  • What I know is, I need to retrieve the response[0]['player'] – Mamdouh Morad Dec 05 '22 at 19:12
  • 1
    OK I found the solution to my issue :) – Mamdouh Morad Dec 05 '22 at 20:39