angulartypescriptrxjsobservableasync-pipe

Proper Way for Handling Observables for Async Pipe Rendering


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


Solution

  • 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));
    }