Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parse information from a Hal+JSON object in Angular 2

I have a spring-data-rest repository producing a hal+json object that I'd like my Angular 2 front end to receive and display.

Hal+Json Object:

{
  "_embedded" : {
    "users" : [ {
      "name" : "Bob",
      "_links" : {
        "self" : {
          "href" : "http://localhost:4200/api/users/1"
        },
        "user" : {
          "href" : "http://localhost:4200/api/users/1"
        }
      }
    }, {
      "name" : "Joe",
      "_links" : {
        "self" : {
          "href" : "http://localhost:4200/api/users/2"
        },
        "user" : {
          "href" : "http://localhost:4200/api/users/2"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:4200/api/users"
    },
    "profile" : {
      "href" : "http://localhost:4200/api/profile/users"
    },
    "search" : {
      "href" : "http://localhost:4200/api/users/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 2,
    "totalPages" : 1,
    "number" : 0
  }
}

I have a service that does a get request to this api.

user.service.ts:

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { User } from './user.model';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map'

@Injectable()
export class UserService {

  constructor(private http: Http) {
  }

  findAllUsers(): Observable<Array<User>> {
    return this.http.get('/api/users')
      .map((response: Response) => response.json())
      .map((data: Array<User>) => {
        return data;
      });
  }
}

Then my users.component calls the findAllUsers method from the service.

users.component.ts

import { Component, OnInit } from '@angular/core';
import { User } from './user.model';
import { UserService } from './user.service';

@Component({
  selector: 'app-users',
  providers: [UserService],
  templateUrl: './users.component.html',
  styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {
  users: User[];

  constructor(private userService: UserService) {
  }

  ngOnInit(): void {
   this.userService.findAllUsers().subscribe((data: Array<User>) => {
     this.users = data;
   });
  }

}

Finally, users.component.html:

<h4>Users:</h4>

<div *ngFor="let user of users">
  {{user}}
</div>

On my view I get an error stating that: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays. I'm not sure how to solve this.

If I try to use the debugger before data is returned in the service, then I can see my hal+json object = data, and I can see the correct information I want from data._embedded_users. But that cannot be mapped to User[] because _embedded isn't a property of my user model. Do I need to do something to the Hal+Json object first?

like image 345
mookamooka Avatar asked Apr 14 '17 01:04

mookamooka


1 Answers

Do I need to do something to the Hal+Json object first?

Is it not obvious? Just extract the data in the service

findAllUsers(): Observable<Array<User>> {
  return this.http.get('/api/users')
    .map((response: Response) => response.json())
    .map((data: any) => {
      return data._embedded.users as User[];
    });
}

What you had before

.map((data: Array<User>) => {
  return data;
});

is incorrect, as you made the assumption that the data being passed to the second map is the array of users, when actually it's the whole HAL object. Changing it to any allows you two extract the users from it.

like image 158
Paul Samsotha Avatar answered Oct 13 '22 02:10

Paul Samsotha