0

I'm trying to display JSON response but I get this error: core.js:6185 ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed.

Error Img

How can I solve this issue? How can I convere it to array ?

TS

export interface Book {
  id: number,
  book_name: string,
  book_issue: Date,

}

Service.ts

export class BookApiService {
  private bookUrl  = "http://127.0.0.1:5000/books"
  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json'
    })
  }
    constructor (private http: HttpClient){}

    getBook(): Observable<Book[]> {
      return this.http.get<Book[]>(this.bookUrl ,this.httpOptions)
      .pipe(
        catchError(this.errorHandler)
      )
      }
  
  errorHandler(error) {
    let errorMessage = '';
    if(error.error instanceof ErrorEvent) {
      errorMessage = error.error.message;
    } else {
      errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    return throwError(errorMessage);
 }

template

<ul *ngFor="let book of books">
    <li>{{book.book_name}}</li>
</ul>

Component

export class AppComponent implements OnInit {
  title = 'app';
  books: Book[] = [];

  constructor(public rs : BookApiService){}

  ngOnInit(): void {
    this.rs.getBook().subscribe((data: Book[])=>{
      this.books = data;
      console.log(this.books);
    })  
  }

Backend API Response:

{"books":[{"book_issue":"Fri, 13 Mar 2020","book_name":"Book1","id":1},
{"book_issue":"Fri, 13 Mar","book_name":"Book2",                                                                                                                                                                                                "id":2}],
"success":true}                                                                                                                                                                                           

and this is the console log: console Log

1
  • 1
    *ngFor="let book of books.books"..? Commented Aug 17, 2020 at 13:52

3 Answers 3

2

Update your code as below :

<ul *ngFor="let book of books?.books">
    <li>{{book.book_name}}</li>
</ul>

The response returned from your API is an object and you are assigning it to the variable used in ngFor , which expects an array. so its throwing error.

Another way to solve this would be to assign your variable as below :

this.rs.getBook().subscribe((data: any)=>{
      this.books = data.books;
      console.log(this.books);
    }) 

and then in your html use this as below :

<ul *ngFor="let book of books">
    <li>{{book.book_name}}</li>
</ul>
Sign up to request clarification or add additional context in comments.

3 Comments

@FaDATA yeah you should remove Book[] because you are not getting response as an array
It Is better to create an interface BooksModel{books: Book[] }and return the Observable<BooksModel>.
Of if possible to change the api reponse to return the data that must be used.
1

try doing

getBooks(): Observable<Book []> {
  return this.http.get<{books: Book[]}>(this.bookUrl, this.httpOptions)
           .pipe(
              map(response => response.books)
            )
}
     

Comments

0

You said the following is the Response:

{"books":[{"book_issue":"Fri, 13 Mar 2020","book_name":"Book1","id":1},
{"book_issue":"Fri, 13 Mar","book_name":"Book2",                                                                                                                                                                                                "id":2}],
"success":true}

that is wrong since the object you get is not a array of books.

It is a JSON Object with the Key books that contains a Array of books.

If this is the case:

EDIT you do can do this, since the response does not give you an array in the body:

this.rs.getBook().subscribe((data: object)=>{
      this.books = data['books'];
      console.log(this.books);
    })  

or you could define a wrapper class:

export class BookResponse{
 books: Book[];
 success: boolean;
}

    getBook(): Observable<Book[]> {
      return this.http.get<BookResponse>(this.bookUrl ,this.httpOptions)
      .pipe(
        catchError(this.errorHandler)
      ).pipe(map(body => body.books))
      }

this.rs.getBook().subscribe((data: Book[])=>{
      this.books = data;
      console.log(this.books);
    })  

5 Comments

I don't think this is a good solution because the service says that the method should return an Observable of Book array. In this case is not and this is a bit inconsistent from my point of view.
then the restmethod needs to return a Observable<{[string]:Book[]]}> or even Observable<object> . The REST-Endpoint dictats how the corrosponding rest interfaces should look like. if the Entpoint returns a array you should use an array. but you get a Wrapper with a key that contains a array. this will not be properly converted, since JavaScript/Typscript is not typesafe. It will parse the object like it is, even if you want an Array. You still get an Object with a key that cointains an array of books. You can also define a Corrosponding object to the endpoint response.
I agree that this also solve the problem, but I guess the answer from @markpenaranda is the best for this special case.
@RicardoFerreira it depends. You still have a service that indicates that you get a restcall and EXPECT an array. But you do not get an Array as Response. either you map it via pipe(map(response = >response.books)) to the desired field or you redefine the call to a proper responsebody type. Thats the whole reason why angular Uses Typescript in the first place. You should define what you get and get what you expect via definition.
Yes, but right now the consumer is receiving a Book[ ] and not an object anymore. the map is returning what is expected. Of course it could be better to create a interface with the api response, or even better to change the api to return what is expected.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.