nck
nck

Reputation: 2221

How can I return an array inside a key of a json in a service in Angular?

I have been following the tutorial of the heroes in angular, and then I wanted to apply it to my small test project to consolidate it. When I was using it with the built in http server and some mock items, it worked, but now I am not able to retrieve the items I want from another a Django REST API.

I can test that this is my API and works:

curl -H 'Accept: application/json; indent=4' http://127.0.0.1:5000/inventory/items_viewset/ -L
{
    "count": 13,
    "next": "http://127.0.0.1:5000/inventory/items_viewset/?page=2",
    "previous": null,
    "results": [
        {
            "label": "00004",
            "name": "Test2",
            "notes": "222",
            "owner": "admin",
            "photo": null
        },
        {
            "label": "0000007",
            "name": "Test1",
            "notes": null,
            "photo": "http://127.0.0.1:5000/media/item_images/2021/02/19/IMG_20210207_134147.jpg"
        },
    ]
}

Then I have my Item item.ts

export interface Item {
  label: string;
  name: string;
  notes: string;
}

I have a component displaying those items items.component.ts:

    items: Item[];  

    constructor(private itemService: ItemService, private messageService: MessageService) { }
    // constructor() { }

    ngOnInit(): void {
        this.getItems();
    }

    
    getItems(): void {
        this.itemService.getItems()
            .subscribe(items => this.items = items);
    }

And here I have the service where I am trying to do the changes

import { Injectable } from '@angular/core';
import { Item } from './item';
import { ITEMS } from './mock-items';
import { Observable, of } from 'rxjs';
import { MessageService } from './message.service';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, tap, map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class ItemService {

    constructor(  private http: HttpClient, private messageService: MessageService) { }
  
    private itemsUrl = 'http://127.0.0.1:5000/inventory/items_viewset';  // URL to web api
    
    httpOptions = {
        headers: new HttpHeaders({ 'Content-Type': 'application/json',  })
    };
  
    getItems(): Observable<Item[]> {
return this.http.get<Item[]>(this.itemsUrl).pipe(
            map(res => res ),
            tap(_ => this.log('fetched items')),
            catchError(this.handleError<Item[]>('getItems', []))
        );  
    }
    
    
    /**
    * Handle Http operation that failed.
    * Let the app continue.
    * @param operation - name of the operation that failed
    * @param result - optional value to return as the observable result
    */
    private handleError<T>(operation = 'operation', result?: T) {
        return (error: any): Observable<T> => {

            // TODO: send the error to remote logging infrastructure
            console.error(error); // log to console instead

            // TODO: better job of transforming error for user consumption
            this.log(`${operation} failed: ${error.message}`);
            console.error(`${operation} failed: ${error.message}`);

            // Let the app keep running by returning an empty result.
            return of(result as T);
        };
    }
    
      /** Log a HeroService message with the MessageService */
    private log(message: string) {
        this.messageService.add(`ItemService: ${message}`);
    }
}

It may be a little bit messy, as I removed irrelevant stuff, but the only point where I have been working since I switched to the real API is this method:

getItems(): Observable<Item[]> {
return this.http.get<Item[]>(this.itemsUrl).pipe(
            map(res => res ),
            tap(_ => this.log('fetched items')),
            catchError(this.handleError<Item[]>('getItems', []))
        );  
    }

I have been already more than one day in my free time trying to fix this but I am not able to find how can I access the key results from the JSON in order to map it to the Item. Most of the similar questions I find make use of a function .json() which I think I have understood is not used anymore in HttpClient. Then I have also tried in many forms something like res.results without success, I get an exception that that property does not exist.

The query is working, as If I change the tap line to:

tap(_ => console.log(_)),

I get the Object in an error.

Can someone give me some hint on what I am doing wrong?. I don't know where else to search I can't make it work from the tutorial, and the documentation from https://angular.io/api/common/http/HttpClient I think does also not cover this, and I think it should be quiet simple, but I have no idea how can I further debug.

Upvotes: 1

Views: 388

Answers (1)

nck
nck

Reputation: 2221

I think I finally make it work but I don't know if this is the right approach if I want to use this function in many places as I need a lot of code in the component, but probably If I work on pagination request I would also need anyway the other parameters.

As suggested by @jonrsharpe I removed the Item and change it to any, and then I could do some parsing in the response in the component: Son in my service I have item.service.ts:

    getAllItems(): Observable<any> {
        return this.http.get(this.itemsUrl).pipe(
            tap(_ => this.log('fetched items')),
            catchError(this.handleError<Item[]>('getItems', []))
        );  
    }

And In my component I work with the JSON items.component.ts:

    items: Item[];  
    next: string;
    previous: string;

    ngOnInit(): void {
        this.getItems();
    }

    getItems() {
        this.itemService.getAllItems().subscribe(
            res => {
                console.log(res);
                if (res.results) {
                    this.items = res.results;
                }
                if (res.next) {
                    // set the components next transactions here from the response
                    this.next = res.next;
                    console.log(this.next);
                }
                if (res.previous) {
                    // set the components previous transactions here from the response
                    this.previous = res.previous;
                }
            }, 
            error => {console.log(error)}
        );
      }

I won't set the question as resolved, as I'm just a beginner and I have no idea if this is the right approach. But at least It seems to work in my scenario.

Upvotes: 1

Related Questions